now I am using recompose to create HOC for my stateless component, and I use withState to hold the inner state in the HOC, and this state is initial from the pass in props. this is work fine in the mount period, but I don't know how to handle the state change from props at the update period, i just want to use lifecycle componentWillReceiveProps to handle that, but nothing happened. so anyone can help me on this?
the code just like below:
compose(
withState('counter', 'updateCounter', ({ outerCounter }) =>outerCounter ),
lifecycle({
componentWillReceiveProps(nextProps) {
if(this.props.outerCounter !== nextProps.outerCounter) {
this.props.updateCounter(nextProps.outerCounter);
}
}
})
)({ counter, updateCounter } => (
<div>
<div>{counter}</div>
<button onClick={
() => updateCounter(counter++)
}>Add counter</button>
</div>
));
we can see my purpose is to pass a counter the component, and click the button we can change the counter, but we also can change the counter from outside of component, it can also effect the inner value. I don't know how to implement it by using recompose. I know we can update state at lifecycle method componentWillReceiveProps, but seems it hard to write it in recompose way
Hi,
At first I want to say that state dependent of props is not a good idea and always can be fixed by moving it upper in a tree. Sometimes can be fixed by using props and state to calculate anything you need on the fly without updating state itself.
Why it's not good idea:
But, sometimes it's hard to move state upper in a tree, sometimes we need to encapsulate such logic inside component without affecting other components, and sometimes we just have no time, and even I wrote that it's not good idea, I can't say that it's very bad idea.
In recompose the only good way to work with such state is to use mapPropsStream enhancer, as all other ways have drawbacks, so in simplest form it will be something like this
mapPropsStream(props$ => props$.scan( /* here logic to update state */ ))
yes I agree with you, but sometime we need encapsulate the state with component that will make the component expose less api for other users( developers ), so this is why I need put the state into the component scope, right now i have no good idea to handle it.
I want to propose two ways for this use case:
outerCounter prop into the componentcompose(
withState('counter', 'updateCounter', 0),
)({ outerCounter = 0, counter, updateCounter } => (
<div>
<div>{outerCounter + counter}</div>
<button onClick={
() => updateCounter(counter++)
}>Add counter</button>
</div>
));
It is very similar to counter example from docs, but we need to get latest props value:
const count$ = props$
.pluck(['counter'])
.combineLatest(delta$, (counter, delta) => counter + delta)
@evenchange4 how should I implement it without Rxjs? do you have some idea
@dingchaoyan1983 Have you tried to use ++counter instead of counter++? It seems like fix your problem.
let counter = 1
console.log(counter++) // log 1
console.log(++counter) // log 3
IMO always writing counter + 1 is a good practice.
I am going to close this issue now. Feel free to reopen it if you have further questions.
Greetings
i have doubts about how to use mapPropsStream or componentFromStream to update my state on props change. For example i have this:
const Item = withState('checked', 'setChecked', false)(
({ checked, setChecked }) => (
<Checkbox checked={checked} onChange={({ target }) => setChecked(target.checked)} />
)
)
const App = withState('checkedAll', 'setCheckedAll', false)(
({ checkedAll, setCheckedAll }) => (
<div>
<Checkbox checked={checkedAll} onChange={({ target }) => setCheckedAll(target.checked)} />
<List>
<Item checked={checkedAll} />
<Item checked={checkedAll} />
<Item checked={checkedAll} />
<Item checked={checkedAll} />
<Item checked={checkedAll} />
<Item checked={checkedAll} />
<Item checked={checkedAll} />
</List>
</div>
)
)
the problem here is when i try to check all my items it does not work, i have tried with mapPropsStream and componentFromStream according to comments above but it doesn't work.
Can you give me more explicit example about how to use mapPropsStream or componentFromStream in this case.
Thanks.
Most helpful comment
Hi,
At first I want to say that state dependent of props is not a good idea and always can be fixed by moving it upper in a tree. Sometimes can be fixed by using props and state to calculate anything you need on the fly without updating state itself.
Why it's not good idea:
But, sometimes it's hard to move state upper in a tree, sometimes we need to encapsulate such logic inside component without affecting other components, and sometimes we just have no time, and even I wrote that it's not good idea, I can't say that it's very bad idea.
In recompose the only good way to work with such state is to use
mapPropsStreamenhancer, as all other ways have drawbacks, so in simplest form it will be something like this