Provavelmente estou perdendo algo muito óbvio e gostaria de me esclarecer.
Aqui está o meu entendimento.
Em um componente de reação ingênuo, temos states
& props
. Atualizar state
com setState
renderiza novamente todo o componente. props
são geralmente somente leitura e atualizá-los não faz sentido.
Em um componente react que se inscreve em um redux store, por meio de algo parecido store.subscribe(render)
, ele obviamente se refaz a cada vez que o store é atualizado.
react-redux tem um helper connect()
que injeta parte da árvore de estado (que é de interesse para o componente) e actionCreators quanto props
ao componente, geralmente por meio de algo como
const TodoListComponent = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
Mas, com o entendimento de que um setState
é essencial para a TodoListComponent
reagir à mudança árvore do estado redux (re-rendem), eu não consigo encontrar nenhuma state
ou setState
código relacionado no TodoList
arquivo de componente. É mais ou menos assim:
const TodoList = ({ todos, onTodoClick }) => (
<ul>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
)
Alguém pode me apontar na direção certa sobre o que estou perdendo?
PS Estou seguindo o exemplo de lista de tarefas que vem junto com o pacote redux .
fonte
prev.a === current.a && prev.b === current.b && .....
. Isso pressupõe que quaisquer alterações de dados resultarão em novas referências, o que significa que atualizações de dados imutáveis são necessárias em vez de mutação direta.Minha resposta está um pouco fora do campo esquerdo. Ele lança luz sobre um problema que me levou a este post. No meu caso, parecia que o aplicativo não estava sendo renderizado novamente, embora recebesse novos adereços.
Os desenvolvedores do React tiveram uma resposta para essa pergunta frequente, algo que diz que se o (armazenamento) sofreu uma mutação, 99% das vezes esse é o motivo pelo qual o react não renderá novamente. Ainda nada sobre os outros 1%. Mutação não era o caso aqui.
TLDR;
Borda de caso: Uma vez que
state
as atualizações, em seguida, o aplicativo faz re-render!Acontece que se seu aplicativo está usando apenas
state
para exibir seus elementos,props
pode atualizar, masstate
não fará, portanto, não renderizará novamente.Eu tinha
state
que depender doprops
recebido do reduxstore
. Os dados de que eu precisava ainda não estavam na loja, então eu os busqueicomponentDidMount
, como é apropriado. Eu recebi os adereços de volta, quando meu redutor atualizou a loja, porque meu componente está conectado via mapStateToProps. Mas a página não foi renderizada e o estado ainda estava cheio de strings vazias.Um exemplo disso é dizer que um usuário carregou uma página de "edição de postagem" de um url salvo. Você tem acesso a
postId
do url, mas a informação ainda nãostore
foi encontrada, então você a busca. Os itens em sua página são componentes controlados - portanto, todos os dados que você está exibindo estão emstate
.Usando redux, os dados foram buscados, o armazenamento foi atualizado e o componente é
connect
editado, mas o aplicativo não refletiu as alterações. Olhando mais de perto,props
foram recebidos, mas o aplicativo não foi atualizado.state
não atualizou.Bem,
props
será atualizado e propagado, masstate
não. Você precisa informar especificamentestate
para atualizar.Você não pode fazer isso em
render()
, ecomponentDidMount
já terminou seus ciclos.componentWillReceiveProps
é onde você atualizastate
propriedades que dependem de umprop
valor alterado .Exemplo de uso:
componentWillReceiveProps(nextProps){ if (this.props.post.category !== nextProps.post.category){ this.setState({ title: nextProps.post.title, body: nextProps.post.body, category: nextProps.post.category, }) } }
Devo agradecer a este artigo que me iluminou sobre a solução que dezenas de outros posts, blogs e repositórios deixaram de mencionar. Qualquer outra pessoa que teve problemas para encontrar uma resposta para este problema evidentemente obscuro, aqui está:
Métodos de ciclo de vida do componente ReactJs - um mergulho profundo
fonte
React 16.3
partir de agora, você deve usar o emgetDerivedStateFromProps
vez decomponentWillReceiveProps
. Mas, na verdade, você nem deve fazer tudo isso conforme articulado aquiEsta resposta é um resumo do artigo de Brian Vaughn intitulado Você provavelmente não precisa do estado derivado (7 de junho de 2018).
Derivar o estado dos adereços é um antipadrão em todas as suas formas. Incluindo o uso do mais antigo
componentWillReceiveProps
e do mais recentegetDerivedStateFromProps
.Em vez de derivar o estado dos adereços, considere as seguintes soluções.
Duas recomendações de melhores práticas
Recomendação 1. Componente totalmente controlado
Recomendação 2. Componente totalmente não controlado com uma chavefunction EmailInput(props) { return <input onChange={props.onChange} value={props.email} />; }
// parent class class EmailInput extends Component { state = { email: this.props.defaultEmail }; handleChange = event => { this.setState({ email: event.target.value }); }; render() { return <input onChange={this.handleChange} value={this.state.email} />; } } // child instance <EmailInput defaultEmail={this.props.user.email} key={this.props.user.id} />
Duas alternativas se, por qualquer motivo, as recomendações não funcionarem para sua situação.
Alternativa 1: redefinir o componente não controlado com um ID prop
Alternativa 2: redefinir o componente não controlado com um método de instânciaclass EmailInput extends Component { state = { email: this.props.defaultEmail, prevPropsUserID: this.props.userID }; static getDerivedStateFromProps(props, state) { // Any time the current user changes, // Reset any parts of state that are tied to that user. // In this simple example, that's just the email. if (props.userID !== state.prevPropsUserID) { return { prevPropsUserID: props.userID, email: props.defaultEmail }; } return null; } // ... }
class EmailInput extends Component { state = { email: this.props.defaultEmail }; resetEmailForNewUser(newEmail) { this.setState({ email: newEmail }); } // ... }
fonte
como eu sei que a única coisa que o redux faz, na mudança de estado da loja está chamando componentWillRecieveProps se seu componente era dependente de um estado mutado e então você deve forçar seu componente a atualizar é assim
Alteração de estado de 1 loja-2 chamadas (componentWillRecieveProps (() => {alteração de estado de 3 componentes}))
fonte