I want my App
component to display keys every time keys
changes. I'm doing this by passed keys as a prop
of App
:
import * as React from "react";
import { render } from "react-dom";
import { useState, useEffect } from "react"
let keys: string[] = [];
// This is what is supposed to happen in the real app
// document.addEventListener("keypress", (event) => {
// keys.push(event.key)
// });
setTimeout(() => {
keys.push('a');
}, 1000)
function App({ keys }: { keys: string[] }) {
let [keysState, setKeysState] = useState(keys)
useEffect(() => {
setKeysState(keys)
}, [keys])
return (
<div>
{keysState.map((key: string) => (
<li>{key}</li>
))}
</div>
);
}
const rootElement = document.getElementById("root");
render(<App keys={keys} />, rootElement);
However, App isn't re-rendering and displaying keys new value:
https://codesandbox.io/s/changing-props-on-react-root-component-forked-3mv0xf?file=/src/index.tsx
Why is this, and how to fix it?
Note: I tried: setKeysState([...keys, 'a'])
. That doesn't re-render App
either.
Live code: https://codesandbox.io/s/changing-props-on-react-root-component-forked-3mv0xf?file=/src/index.tsx
CodePudding user response:
All data that is dynamic needs to be managed by React. Put your event inside the component and update local state.
function App({ initialKeys }: { initialKeys: string[] }) {
const [keys, setKeys] = React.useState(initialKeys);
console.log(keys);
React.useEffect(() => {
const append = (e) => {
setKeys([...keys, e.key]);
};
document.addEventListener("keypress", append);
return () => {
document.removeEventListener("keypress", append);
};
}, [keys]);
return (
<div>
{keys.map((key: string, idx) => (
<li key={idx}>{key}</li>
))}
</div>
);
}
https://codesandbox.io/s/changing-props-on-react-root-component-forked-l869dd?file=/src/index.tsx
CodePudding user response:
if you use the below strategy it works as you want it to work. React cannot see state changes out of its built-in functions so it didn't track the change on your array which was out of its state scope
import * as React from "react";
import { render } from "react-dom";
import { useState, useEffect } from "react";
let keys: string[] = [];
function App(props: any) {
const [keys, oldKeysState] = useState(props.keys);
const [keysState, setKeysState] = useState(keys);
useEffect(() => {
setKeysState(keys);
}, [keys]);
// componentWillMount
useEffect(() => {
setTimeout(() => {
oldKeysState([...keys, "a"]);
}, 1000);
}, []);
return (
<div>
{keysState.map((key: string) => (
<li>{key}</li>
))}
<button onClick={() => setKeysState([...keysState, " "])}> </button>
</div>
);
}
const rootElement = document.getElementById("root");
render(<App keys={keys} />, rootElement);