Something like:
class Parent extends Component {
render() {
return (
<MenuElem isSelected={false} />
<MenuElem isSelected={true} />
);
}
}
class MenuElem extends Component {
render() {
return (
<li onClick={() => this.setState({isSelected: true})} className={this.props.isSelected ? "is-active" : ""}>
</li>
);
}
}
Why the isSelected props dont update when I fire the click event ? How can i add the "is-active" class when I click ?
答案 0 :(得分:2)
You are mixing props
and state
together in your logic.
props
are external parameters that a component receives from its
parent. They are read only and can't be changed by the child.state
is a local object that gets updated. local in a way that only
the very same component "knows" about it.In your example, you are passing a Boolean isSelected
from a parent to a child, then inside the child's (MenuElem
) onClick
event you are creating a local Boolean isSelected
(inside the local state object) but when you conditionally passing the CSS
style you are checking the prop
isSelected
passed via the parent, which will can't changed by the child as it is a read only property.
You can either check the this.state.isSelected
or just pass an updated props.isSelected
from the parent. The second choice will mean you need to manage the state at the parent level.
Small example for local state inside the child:
class Parent extends React.Component {
render() {
return (
<MenuElem />
);
}
}
class MenuElem extends React.Component {
state = {
isSelected: false
}
render() {
const { isSelected } = this.state;
return (
<li onClick={() => this.setState({ isSelected: true })} style={{ color: isSelected ? 'green': 'initial' }}>
item
</li>
);
}
}
ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Example for parent state, note that it is advice to keep track for the id's so you can signal the parent which child was being clicked:
class Parent extends React.Component {
state = {
items: [
{ id: 1, name: 'item 1', selected: false },
{ id: 2, name: 'item 2', selected: true }]
}
onItemClick = itemId => {
this.setState(prev => {
const nextItems = prev.items.map(item => {
return {
...item,
selected: item.id === itemId
}
});
return { items: nextItems };
})
}
render() {
const { items } = this.state;
return (
<div>
{
items.map(item => (
<MenuElem
key={item.id}
{...item}
onClick={this.onItemClick}
/>
))
}
</div>
);
}
}
class MenuElem extends React.Component {
onClick = () => {
const { onClick, id } = this.props;
onClick(id);
}
render() {
const { selected, name } = this.props;
return (
<li
onClick={this.onClick}
style={{ color: selected ? 'green' : 'initial' }}>
{name}
</li>
);
}
}
ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
答案 1 :(得分:1)
props
and state
are different things. Your MenuElem
component know about isSelected
as props
, not state
. So no setState
for the guy. Two options:
1) isSelected
is in state in Parent
component and you pass it as props to MenuElem
among a callback to do the setState
(but the state belongs to Parent
)
2) Parent
stays the same and you assign isSelected
to state for MenuElem
(then you can do a setState
, and in this case the state is in MenuElem
)
答案 2 :(得分:1)
You can fix your script by making sure MenuElem
is statefull, in this way you can set its own internal state based on your event (onClick for instance).
Example:
class MenuElem extends React.Component {
state = {
isSelected: false
}
render() {
return (
<li onClick={() => this.setState({ isSelected: true })} style={{ color: isSelected ? 'green': 'initial' }}>
item
</li>
);
}
}
Or if you need only props you can do
class MenuElem extends React.Component {
render() {
return (
const { isSelected } = this.props
<li onClick={() => this.setState({ isSelected })} style={{ color: isSelected ? 'green': 'initial' }}>
item
</li>
);
}
}