React Router 4 - Switch 上的受控组件不是 Un-Mounting
React Router 4 - Controlled Component not Un-Mounting on Switch
我正在尝试学习如何将状态从 <Child/>
提升到 <Parent/>
并使 parent 控制用户交互完成child,(接收 state down 作为道具)即显示颜色和文本。
我能够提升状态。但是,当我 switch 在路由之间来回切换时, <Parent/>
组件不是 re-mounting 并且它的状态仍然与之前 setState({})
设置的完全一样
const cars = [
{ name: "Ferrari", cost: ".000", color: "red", id: 1 },
{ name: "Porsche", cost: ".000", color: "black", id: 2 },
***
];
class Dealership extends Component {
state = {
cars,
isShow: {},
correctIndex: Math.floor(Math.random() * (cars.length - 1))
};
handleShuffle = () => {
this.setState({
cars: [...this.state.cars.sort(() => Math.random() - 0.5)],
isShow: {}
});
};
handleShow = car => {
const { isShow } = this.state;
console.log("isShow=", isShow);
this.setState(currentState => ({
isShow: { ...currentState.isShow, [car]: true }
}));
};
render() {
return (
<>
<Navigation />
<Routes
state={this.state}
shuffle={this.handleShuffle}
handleShow={this.handleShow}
// isShow={this.state.isShow}
/>
</>
);
}
}
export default withRouter(Dealership);
如上所述,child <Car/>
正在接收状态作为道具,以便其用户交互可以由一个真实来源控制parent <Dealership />
export default class Car extends Component {
render() {
const { cars, shuffle, isShow, handleShow, correctIndex } = this.props;
const correctCar = cars[correctIndex];
const car = cars.map(car => (
<CarList
// {...this.state}
isShow={isShow[car.name]}
key={car.id}
car={car.name}
guess={car.cost}
isCorrect={correctCar.cost === car.cost}
handleShow={handleShow}
/>
));
return (
<>
<Question key={correctCar.id} guess={correctCar.cost} />
<button
onClick={() => {
shuffle();
}}
>
go again
</button>
<ul className="car-list">{car}</ul>
</>
);
}
}
这里把<CarList/>
抽象出来:
// CarList.js
export const CarList = ({ isShow, isCorrect, car, handleShow, guess }) => {
function getColor() {
if (isShow) {
const showColor = isCorrect ? "green" : "red";
return showColor;
}
return "";
}
return (
<li onClick={() => handleShow(car)} className={getColor()}>
{car}
<span className={isShow ? "show" : "hide"}>{guess}</span>
</li>
);
};
奇怪的是(对我来说),当我切换到一条拥有自己的本地状态的路由时,即 <Bike/>
,一切都按预期工作(状态恢复到原始状态)
import React, { useState } from "react";
export const Bike = () => {
const [color, setColor] = useState(false);
function ChangeColor() {
setColor(true);
}
return (
<p onClick={ChangeColor}>
Click on the <span className={color ? "red" : " "}>Bike</span>
</p>
);
};
这是我设置路线的方式:
// Navigation.JS
export const Navigation = () => (
<nav>
<ul>
<li>
<Link to="/">home</Link>
</li>
<li>
<Link to="/car-cost">car</Link>
</li>
<li>
<Link to="/bike">bike</Link>
</li>
</ul>
</nav>
);
// Routes.js
export const Routes = ({ state, shuffle, handleShow, isShow }) => (
<Switch>
<Route
path="/car-cost"
render={() => (
<Car
{...state}
shuffle={shuffle}
handleShow={handleShow}
// isShow={isShow}
/>
)}
/>
<Route path="/bike" render={() => <Bike />} />
<Route path="/" component={Home} />
</Switch>
);
然后我用 <BrowserRouter />
包装了我的主应用程序,如您所见,加上当前在此 code sandbox
上发生的不当行为
如何在 <Car/>
表现如 <Bike/>
的路由 之间切换?即 return 到其原始状态 。另外,我在这里正确地提升和控制状态了吗?
这里的状态被保存在父组件中。当路线改变时,只有子组件被重新安装。因此,父组件的状态在整个路由过程中都保持在那里。
您可以将状态保留在子组件中,这将在每次卸载后重置状态。但是,如果您想提升状态并仍然重置状态,则必须在父组件中执行此操作。
更好的方法是在父组件中监控路由变化。如果路由已更改,则父组件应重置其状态。在父组件的componentDidUpdate
方法中,你可以像这样跟踪路由变化和重置状态
componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
console.log('Route change! Reset the state');
this.setState({ isShow: {}})
}
}
我正在尝试学习如何将状态从 <Child/>
提升到 <Parent/>
并使 parent 控制用户交互完成child,(接收 state down 作为道具)即显示颜色和文本。
我能够提升状态。但是,当我 switch 在路由之间来回切换时, <Parent/>
组件不是 re-mounting 并且它的状态仍然与之前 setState({})
设置的完全一样
const cars = [
{ name: "Ferrari", cost: ".000", color: "red", id: 1 },
{ name: "Porsche", cost: ".000", color: "black", id: 2 },
***
];
class Dealership extends Component {
state = {
cars,
isShow: {},
correctIndex: Math.floor(Math.random() * (cars.length - 1))
};
handleShuffle = () => {
this.setState({
cars: [...this.state.cars.sort(() => Math.random() - 0.5)],
isShow: {}
});
};
handleShow = car => {
const { isShow } = this.state;
console.log("isShow=", isShow);
this.setState(currentState => ({
isShow: { ...currentState.isShow, [car]: true }
}));
};
render() {
return (
<>
<Navigation />
<Routes
state={this.state}
shuffle={this.handleShuffle}
handleShow={this.handleShow}
// isShow={this.state.isShow}
/>
</>
);
}
}
export default withRouter(Dealership);
如上所述,child <Car/>
正在接收状态作为道具,以便其用户交互可以由一个真实来源控制parent <Dealership />
export default class Car extends Component {
render() {
const { cars, shuffle, isShow, handleShow, correctIndex } = this.props;
const correctCar = cars[correctIndex];
const car = cars.map(car => (
<CarList
// {...this.state}
isShow={isShow[car.name]}
key={car.id}
car={car.name}
guess={car.cost}
isCorrect={correctCar.cost === car.cost}
handleShow={handleShow}
/>
));
return (
<>
<Question key={correctCar.id} guess={correctCar.cost} />
<button
onClick={() => {
shuffle();
}}
>
go again
</button>
<ul className="car-list">{car}</ul>
</>
);
}
}
这里把<CarList/>
抽象出来:
// CarList.js
export const CarList = ({ isShow, isCorrect, car, handleShow, guess }) => {
function getColor() {
if (isShow) {
const showColor = isCorrect ? "green" : "red";
return showColor;
}
return "";
}
return (
<li onClick={() => handleShow(car)} className={getColor()}>
{car}
<span className={isShow ? "show" : "hide"}>{guess}</span>
</li>
);
};
奇怪的是(对我来说),当我切换到一条拥有自己的本地状态的路由时,即 <Bike/>
,一切都按预期工作(状态恢复到原始状态)
import React, { useState } from "react";
export const Bike = () => {
const [color, setColor] = useState(false);
function ChangeColor() {
setColor(true);
}
return (
<p onClick={ChangeColor}>
Click on the <span className={color ? "red" : " "}>Bike</span>
</p>
);
};
这是我设置路线的方式:
// Navigation.JS
export const Navigation = () => (
<nav>
<ul>
<li>
<Link to="/">home</Link>
</li>
<li>
<Link to="/car-cost">car</Link>
</li>
<li>
<Link to="/bike">bike</Link>
</li>
</ul>
</nav>
);
// Routes.js
export const Routes = ({ state, shuffle, handleShow, isShow }) => (
<Switch>
<Route
path="/car-cost"
render={() => (
<Car
{...state}
shuffle={shuffle}
handleShow={handleShow}
// isShow={isShow}
/>
)}
/>
<Route path="/bike" render={() => <Bike />} />
<Route path="/" component={Home} />
</Switch>
);
然后我用 <BrowserRouter />
包装了我的主应用程序,如您所见,加上当前在此 code sandbox
如何在 <Car/>
表现如 <Bike/>
的路由 之间切换?即 return 到其原始状态 。另外,我在这里正确地提升和控制状态了吗?
这里的状态被保存在父组件中。当路线改变时,只有子组件被重新安装。因此,父组件的状态在整个路由过程中都保持在那里。
您可以将状态保留在子组件中,这将在每次卸载后重置状态。但是,如果您想提升状态并仍然重置状态,则必须在父组件中执行此操作。
更好的方法是在父组件中监控路由变化。如果路由已更改,则父组件应重置其状态。在父组件的componentDidUpdate
方法中,你可以像这样跟踪路由变化和重置状态
componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
console.log('Route change! Reset the state');
this.setState({ isShow: {}})
}
}