问题
I am new to react and trying to update parent's state but no luck so far.
Component
class InputBox extends Component {
constructor(props) {
super(props);
this.type = props.type;
}
render() {
return (
<div>
<input type={this.type}/>
</div>
);
}
}
Other container where I want to use this component to toggle password
constructor(props) {
super(props);
this.state = {
type: 'password',
wording: 'Show',
};
this.changeState = this.changeState.bind(this);
}
changeState() {
const oldState = this.state.type;
const isTextOrHide = (oldState === 'password');
const newState = (isTextOrHide) ? 'text' : 'password';
const newWord = (isTextOrHide) ? 'Hide' : 'Show';
this.setState({
type: newState,
label: newWord,
});
}
<Wrapper>
<InputBox type={this.state.type} />
<Toggle onClick={this.changeState}>{this.state.wording}</Toggle>
</Wrapper>
回答1:
You can do like this:
First, Parent component:
import React, { Component } from 'react';
import { InputBox} from './InputBox'
class componentName extends Component {
state = {
password: '',
type: 'password',
wording: 'Show',
}
handleShow = (word) => {
this.setState({ wording: word })
}
handleChange = (e) => {
if(!this.state.password){
handleShow('Show')
} else {
handleShow('Hide')
}
this.setState({ password: e.target.value })
}
render() {
return (
<div>
<Wrapper>
<InputBox
name='password'
handleChange={this.handleChange}
password={this.state.password}
type={this.state.type} /> .
<Toggle onClick={this.changeState}>{this.state.wording}
</Toggle>
</Wrapper>
</div>
);
}
}
Now the child component:
import React from 'react';
export const InputBox = (props) => (
<input onChange={props.handleChange} value={props.password} type={props.type}/>
)
- The
stateneeds to always remain in the parent and then pass it down throughprops - The children components usually are stateless, which means, they don't need to be a
class(can be just a function that returnsjsx) and the most import, can't havestate(state is only available inClass components)
Always pass the state down to children components
Because no matter how far down the state is, by being passed through props it'll will always change the source, which in this case is the parent, the creator of the state
another important thing:
If you use arrow functions ES6 , there's no need to have a constructor to bind your functions.
Like this: handleSomething = () => { return ... }
another thing:
you don't need the constructor to set the state, you can simply do
state = { }
and it automatically become part of the context this
Thinking this way you'll never fail.
Hope it helped you :)
回答2:
class Child extends Component{
constructor(props){
super(props);
}
render(){
let { parentStateChange } = this.props;
return <input type='text' onChange={parentStateChange}/>
}
}
class Parent extends Component{
constructor(props){
super(props);
this.state = {
content: "Something"
}
this.parentStateChange = this.parentStateChange.bind(this);
}
parentStateChange(event){
let value = event.target.value;
this.setState({
content: value
})
}
render(){
let { content } = this.state;
return <div>
<h2>{content}</h2>
<Child parentStateChange={this.parentStateChange}></Child>
</div>
}
}
I did it by passing a Parent's method to child as a props. Then Child has use this method to change Parent's state. It's called as Callback Functions.
For More References
I think this is useful for you.
回答3:
A more generic (but possibly bad approach). Parent class has a function that is passed as callback to children and allows child calling setState directly. I can only see this useful in a tightly bound small component with a few children or just for proof of concept code.
/**
* This allows children to set state of this object.
* Might be a very bad approach, btw.
*
* @param {object} newState - object to update state.
* @param {func} cb - call back after state is updated.
*/
doSetState = (newState, cb=null) => {
const merge = { ...this.state, ...newState };
cb ? this.setState(merge, cb) : this.setState(merge);
}
来源:https://stackoverflow.com/questions/44661549/how-to-update-parents-state