I want to do something like this:
const GreetingWithCounter = (props) => {
const { name, count } = props;
return (
<div>
<div>Hello {name}</div>
<button onClick={() => render({ ...props, count: count + 1 })}>
{count}
</button>
</div>
);
}
<GreetingWithCounter name="Alice" count={0} />
Ie. I want to re-render a ponent with new values for its props
. Is there a way to do that? Looking through these three questions, I'm seeing ways to re-render a ponent but not with new values for props (1, 2, 3).
Context
I'm thinking about a way to simplify React. I really like the mental model of React being the view layer in MVC, where UI = F(state). But things can get confusing when "state" can e from so many different places: props
, useState
, useReducer
, "raw" useContext
, Redux (which uses useContext
I think), whatever else.
What if everything was just based off of props?
- For local state you'd do what I did in that example above. You'd initialize the local state of
count
when doing<GreetingWithCounter name="Alice" count={0} />
and then update it by re-rendering. This means less DRYness because you'd have to repeat thecount={0}
code instead of only having it once inside ofGreetingWithCounter
. - You'd have to do prop drilling instead of
useContext
stuff. - This approach would probably make React slower.
- Still, I hypothesize 1) that the mental model of having everything ing from props is simpler and 2) that pro outweighs the cons in a non-trivial amount of apps.
I want to do something like this:
const GreetingWithCounter = (props) => {
const { name, count } = props;
return (
<div>
<div>Hello {name}</div>
<button onClick={() => render({ ...props, count: count + 1 })}>
{count}
</button>
</div>
);
}
<GreetingWithCounter name="Alice" count={0} />
Ie. I want to re-render a ponent with new values for its props
. Is there a way to do that? Looking through these three questions, I'm seeing ways to re-render a ponent but not with new values for props (1, 2, 3).
Context
I'm thinking about a way to simplify React. I really like the mental model of React being the view layer in MVC, where UI = F(state). But things can get confusing when "state" can e from so many different places: props
, useState
, useReducer
, "raw" useContext
, Redux (which uses useContext
I think), whatever else.
What if everything was just based off of props?
- For local state you'd do what I did in that example above. You'd initialize the local state of
count
when doing<GreetingWithCounter name="Alice" count={0} />
and then update it by re-rendering. This means less DRYness because you'd have to repeat thecount={0}
code instead of only having it once inside ofGreetingWithCounter
. - You'd have to do prop drilling instead of
useContext
stuff. - This approach would probably make React slower.
- Still, I hypothesize 1) that the mental model of having everything ing from props is simpler and 2) that pro outweighs the cons in a non-trivial amount of apps.
- you are passing hard coded props , so how they will change? – abolfazl shamsollahi Commented Nov 12, 2022 at 8:27
- So you mean, render should take updated prop values and cause a rerender, since the state, props and functions are different for each render cycle, it looks like it could need a wrapper with React.memo that will update the child – Azzy Commented Nov 12, 2022 at 9:41
-
@abolfazlshamsollahi I'm not sure, but what I want to do is get it to re-render with different props. Ie.
render({ ...props, count: count + 1 })
. – Adam Zerner Commented Nov 12, 2022 at 12:58 - @Azzy "So you mean, render should take updated prop values and cause a rerender" Yeah. – Adam Zerner Commented Nov 12, 2022 at 13:23
- 5 If you want to rerender when props change then pass the updated props to your ponent, that's how react works. Anything else is a hack. – morganney Commented Nov 13, 2022 at 13:17
7 Answers
Reset to default 2Props are not supposed to be mutated in React. That is precisely the difference between props and state. The React way to do this is to use state for the count. You can pass the initial state of the count as a prop and do this: const [count, setCount] = useState(initialCount)
. Your onClick
handler would then increment count
, which again is state. I realize that this is not what you want but it's how React works.
In React Props values cannot be changed in child ponent but we can do it in parent ponent.
const GreetingWithCounter = (props) => {
const { name, count, updateCount } = props;
return (
<div>
<div>Hello {name}</div>
<button onClick={updateCount}>{count}</button>
</div>
);
};
function App() {
const [count, setCount] = useState(0);
const updateCount = () => {
setCount(count + 1);
};
return (
<div className='App'>
<h1>Greeting With Counter:</h1>
<GreetingWithCounter
name='Alice'
count={count}
updateCount={updateCount}
/>
</div>
);
}
Appreciate the change you want to point out and value you want to add but there might be some points that you're missing what React conceptually trying to provide with seperation between props and state.
The props within ponents ing with React are specifically conceptually designed to be immutable as per the documentation here.
So what you're trying to do is conceptually not ok for that purpose and violating what React tries to acplish.
Infact you may mention about creating another library/framework which successfully getting it done while introducing props are the new state
concept but in this specific case, there's no possible way to succeed on it in a React way.
You cannot change value of props in child but you have 2 ways to handle it first, I assume that you only want to use count in child ponent and you don't need count value in parent, in this case you can use props.count as initial state, sth like this :
const GreetingWithCounter = props => {
const [count, setCount] = useState(props.count);
const { name } = props;
return (
<div>
<div>Hello {name}</div>
<button onClick={() => setCount(prevState => prevState + 1)}>{count}</button>
</div>
);
};
<GreetingWithCounter name="Alice" count={0} />;
but if you wanna access it's value from parent, it's better to pass setter to child
sth like this :
const GreetingWithCounter = ({name,count,setCount}) => {
return (
<div>
<div>Hello {name}</div>
<button onClick={() => setCount(prevState => prevState + 1)}>{count}</button>
</div>
);
};
const App = ()=>{
const [count, setCount] = useState(0);
return (<GreetingWithCounter name="Alice" count={count} setCount={setCount} />)
}
or if it's child is so deep that you need to send props to all it's tree, its better to use state management like Redux,Context or ...
Is this the way you want to do ? :
import React from 'react'
import ReactDOM from 'react-dom'
export default function renderComponent(Component, props, container) {
ReactDOM.render(<Component {...props} />, container)
}
What you are trying to do goes against the philosophy of state management of react. For correct way to do it, you can check other answers, and even you yourself have posted it in the questions.
But if you really want to do it, behind its magic, React is also just JavaScript. Therefore, we just need to implement the render function outside of React way of thinking. We know that React re-renders on state change magic or on props change. We need to just somehow connect the render method you asked for with set state. Something like the below should work.
const ParentStuff = () => {
const [props, setProps] = useState({ name: "Alice", count: 0 });
render = setProps;
return (<GreetingWithCounter name={props.name} count={props.count} />);
}
let render;
const GreetingWithCounter = props => {
const { name, count } = props;
return (
<div>
<div>Hello {name}</div>
<button onClick={() => render({ ...props, count: count + 1 })}>{count}</button>
</div>
);
};
A lot of people will scream though at code above. It definitely strays away from the intended use.
If you want to go further, you can also just have one state for the entire app, and pass this state fo every ponent. And voila! You just created a singleton state and an uni directional data flow, which is a poor man version of the redux and this will probably kill performance of the webapp, as things like typing each letter in a textbox will re-render the entire page.
As others already mentioned, ponent is either controlled or uncontrolled (or mix of both) in react.
If you keep state in ponent itself - it's uncontrolled. You can reset its state to internal by changing key
prop from parent though.
If you keep state in parent - it's controlled ponent and changes it's state through props/callbacks.
What you have shown in your example, you want to achieve uncontrolled ponent with some syntactic sugar on top.
Example implementation:
const usePropsWithRender = (props) => {
const [currentProps, setCurrentProps] = useState(props);
return {
...currentProps,
render: setCurrentProps,
};
};
const GreetingWithCounter = (props) => {
const { name, count, render } = usePropsWithRender(props);
return (
<div>
<div>Hello {name}</div>
<button onClick={() => render({ ...props, count: count + 1 })}>
{count}
</button>
</div>
);
};
You can reuse usePropsWithRender
through all you project, but it's nothing more than a thin wrapper around useState
. I don't see how it is better than using useState
directly.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744225914a4564003.html
评论列表(0条)