Ich versuche, eine Präsentationskomponente von einer Containerkomponente zu trennen. Ich habe ein SitesTable
und ein SitesTableContainer
. Der Container ist dafür verantwortlich, Redux-Aktionen auszulösen, um die entsprechenden Sites basierend auf dem aktuellen Benutzer abzurufen.
Das Problem ist, dass der aktuelle Benutzer asynchron abgerufen wird, nachdem die Containerkomponente anfänglich gerendert wurde. Dies bedeutet, dass die Containerkomponente nicht weiß, dass sie den Code in ihrer componentDidMount
Funktion erneut ausführen muss, um die an die zu sendenden Daten zu aktualisieren SitesTable
. Ich denke, ich muss die Containerkomponente neu rendern, wenn sich eine ihrer Requisiten (Benutzer) ändert. Wie mache ich das richtig?
class SitesTableContainer extends React.Component {
static get propTypes() {
return {
sites: React.PropTypes.object,
user: React.PropTypes.object,
isManager: React.PropTypes.boolean
}
}
componentDidMount() {
if (this.props.isManager) {
this.props.dispatch(actions.fetchAllSites())
} else {
const currentUserId = this.props.user.get('id')
this.props.dispatch(actions.fetchUsersSites(currentUserId))
}
}
render() {
return <SitesTable sites={this.props.sites}/>
}
}
function mapStateToProps(state) {
const user = userUtils.getCurrentUser(state)
return {
sites: state.get('sites'),
user,
isManager: userUtils.isManager(user)
}
}
export default connect(mapStateToProps)(SitesTableContainer);
reactjs
redux
react-redux
David
quelle
quelle
componentDidMount
wird, ändern densites
Knoten im Anwendungsstatus, der an den übergeben wirdSitesTable
. Der Knoten des SitesStablesites
ändert sich.Antworten:
Sie müssen Ihrer
componentDidUpdate
Methode eine Bedingung hinzufügen .In diesem Beispiel werden
fast-deep-equal
die Objekte verglichen.import equal from 'fast-deep-equal' ... constructor(){ this.updateUser = this.updateUser.bind(this); } componentDidMount() { this.updateUser(); } componentDidUpdate(prevProps) { if(!equal(this.props.user, prevProps.user)) // Check if it's a new user, you can also use some unique property, like the ID (this.props.user.id !== prevProps.user.id) { this.updateUser(); } } updateUser() { if (this.props.isManager) { this.props.dispatch(actions.fetchAllSites()) } else { const currentUserId = this.props.user.get('id') this.props.dispatch(actions.fetchUsersSites(currentUserId)) } }
Verwenden von Haken (Reagieren Sie auf 16.8.0+)
import React, { useEffect } from 'react'; const SitesTableContainer = ({ user, isManager, dispatch, sites, }) => { useEffect(() => { if(isManager) { dispatch(actions.fetchAllSites()) } else { const currentUserId = user.get('id') dispatch(actions.fetchUsersSites(currentUserId)) } }, [user]); return ( return <SitesTable sites={sites}/> ) }
Wenn die Requisite, die Sie vergleichen, ein Objekt oder ein Array ist, sollten Sie
useDeepCompareEffect
stattdessen verwendenuseEffect
.quelle
user
Änderungen die Bereitstellung aufheben und erneut bereitstellen ? Wie teuer ist das?ComponentWillReceiveProps()
wird in Zukunft aufgrund von Fehlern und Inkonsistenzen veraltet sein. Eine alternative Lösung zum erneuten Rendern einer Komponente beim Requisitenwechsel ist die Verwendung vonComponentDidUpdate()
undShouldComponentUpdate()
.ComponentDidUpdate()
wird aufgerufen, wenn die Komponente aktualisiert wird UND wennShouldComponentUpdate()
true zurückgegeben wird (WennShouldComponentUpdate()
nicht definiert,true
wird standardmäßig zurückgegeben).shouldComponentUpdate(nextProps){ return nextProps.changedProp !== this.state.changedProp; } componentDidUpdate(props){ // Desired operations: ex setting state }
Dasselbe Verhalten kann nur mit der
ComponentDidUpdate()
Methode erreicht werden, indem die bedingte Anweisung darin eingeschlossen wird.componentDidUpdate(prevProps){ if(prevProps.changedProp !== this.props.changedProp){ this.setState({ changedProp: this.props.changedProp }); } }
Wenn man versucht, den Status ohne Bedingung oder ohne Definition
ShouldComponentUpdate()
der Komponente festzulegen, wird dies unendlich neu gerendertquelle
componentWillReceiveProps
veraltet ist und gegen die Verwendung empfohlen wird.Sie können einen
KEY
eindeutigen Schlüssel (Kombination der Daten) verwenden, der sich mit Requisiten ändert, und diese Komponente wird mit aktualisierten Requisiten erneut gerendert.quelle
componentWillReceiveProps(nextProps) { // your code here}
Ich denke, das ist das Ereignis, das Sie brauchen.
componentWillReceiveProps
wird ausgelöst, wenn Ihre Komponente etwas über Requisiten erhält. Von dort aus können Sie Ihre Überprüfung durchführen lassen und dann tun, was Sie wollen.quelle
componentWillReceiveProps
veraltet *Ich würde empfehlen, einen Blick auf meine Antwort zu werfen und zu prüfen, ob sie für Ihre Arbeit relevant ist. Wenn ich Ihr eigentliches Problem verstehe, ist es, dass Sie Ihre asynchrone Aktion einfach nicht richtig verwenden und den Redux "Store" aktualisieren, wodurch Ihre Komponente automatisch mit den neuen Requisiten aktualisiert wird.
Dieser Abschnitt Ihres Codes:
componentDidMount() { if (this.props.isManager) { this.props.dispatch(actions.fetchAllSites()) } else { const currentUserId = this.props.user.get('id') this.props.dispatch(actions.fetchUsersSites(currentUserId)) } }
Sollte in einer Komponente nicht ausgelöst werden, sollte dies nach Ausführung Ihrer ersten Anforderung behandelt werden.
Schauen Sie sich dieses Beispiel von Redux-Thunk an :
function makeASandwichWithSecretSauce(forPerson) { // Invert control! // Return a function that accepts `dispatch` so we can dispatch later. // Thunk middleware knows how to turn thunk async actions into actions. return function (dispatch) { return fetchSecretSauce().then( sauce => dispatch(makeASandwich(forPerson, sauce)), error => dispatch(apologize('The Sandwich Shop', forPerson, error)) ); }; }
Sie müssen nicht unbedingt Redux-Thunk verwenden, aber es hilft Ihnen, über solche Szenarien nachzudenken und passenden Code zu schreiben.
quelle
makeASandwichWithSecretSauce
in Ihrer Komponente?Eine benutzerfreundliche Methode ist die folgende: Sobald die Requisiten aktualisiert wurden, wird die Komponente automatisch neu gerendert:
render { let textWhenComponentUpdate = this.props.text return ( <View> <Text>{textWhenComponentUpdate}</Text> </View> ) }
quelle