[英]How can I pass down variables into child component so that they work with React Router?
[英]How would I restructure my React App, so that I can pass state down to a component on a different route
我将三个组件路由到不同的路径。 我想重组我的应用程序,以便我可以通过props将状态从SubmitProject
组件传递到我的Portfolio
组件。我仍然希望它们具有单独的路径,即; /portfolio
和/SubmitProject
我计划打开两个浏览器窗口以测试当我在SubmitProject
上提交表单时它将显示在Portfolio
然后我将使用SubmitProject
将状态持久化到数据库中。
我是否需要将状态App.js
类的顶级组件,然后在其中BrowserRouter
? 如果是这样,如何重新创建从<SubmitProject/>
-> <PortfolioForm/>
-> <FormAdd/>
我期望的目标是,当我在/submit
路线上从FormAdd
组件提交表单时,它将通过/Portfolio
路线上我的Portfolio
组件上的状态输出。
建议使用状态管理器(如上下文api)或其他方法,但我想知道是否存在一种方法来重组我的App,并能够从每个组件和路由共享的顶级组件传递状态。
这是我的相关代码
components/Router.js
import React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import Portfolio from './Portfolio';
import SubmitProject from './SubmitProject';
import App from './App';
const Router = () => (
<BrowserRouter>
<Switch>
<Route exact path="/" component={App}/>
<Route exact path="/portfolio" component={Portfolio}/>
<Route exact path="/submit" component={SubmitProject}/>
</Switch>
</BrowserRouter>
);
export default Router;
components/App.js
//我的路由器应该在这里吗?
import React from 'react';
class App extends React.Component {
render() {
return <div>Test</div>
}
}
export default App;
/components/SubmitProject.js
import React from 'react';
import PortfolioForm from './PortfolioForm';
import Section from './Section';
class SubmitProject extends React.Component {
state = {
sections:{}
};
addSection = section =>{
const sections = {...this.state.sections};
sections[`section${Date.now()}`] = section;
this.setState({
sections: sections
});
}
render() {
return(
<React.Fragment>
<h1>Submit Project</h1>
<h2>Enter Project Data</h2>
<ul className="section">
{Object.keys(this.state.sections).map(key => <Section key={key} details={this.state.sections[key]}/>)}
</ul>
<PortfolioForm addSection={this.addSection} />
</React.Fragment>
)
}
}
export default SubmitProject;
/components/PortfolioForm.js
import React from 'react';
import FormAdd from './FormAdd';
class Portfolio extends React.Component {
render() {
return(
<React.Fragment>
<h1>Submit Form</h1>
<FormAdd addSection={this.props.addSection}/>
</React.Fragment>
)
}
}
export default Portfolio;
/components/FormAdd.js
import React from 'react';
class FormAdd extends React.Component {
nameRef = React.createRef();
createSection = (event) =>{
event.preventDefault();
const section = {
name: this.nameRef.current.value
};
this.props.addSection(section);
};
render() {
return(
<React.Fragment>
<form onSubmit={this.createSection}>
<input type="text" ref={this.nameRef} name="name" placeholder="Name"/>
<button type="submit">+ Add Section</button>
</form>
</React.Fragment>
)
}
}
export default FormAdd;
/components/Portfolio.js
import React from 'react';
class Portfolio extends React.Component {
//CAN I GET STATE FROM SubmitProject.js FILE IN HERE? By Restructuring my App Somehow.
render() {
return(
<React.Fragment>
<h1>Portfolio Page</h1>
<h2>List of projects</h2>
</React.Fragment>
)
}
}
export default Portfolio;
更新的代码,现在我得到一个错误,提示FooContext is not defined
components/App.js
import React from 'react';
import SubmitProject from './SubmitProject';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
const FooContext = React.createContext();
class App extends React.Component {
state = {
sections:{}
};
addSection = section =>{
const sections = {...this.state.sections};
sections[`section${Date.now()}`] = section;
this.setState({
sections: sections
});
}
render() {
return (
<FooContext.Provider value={this.state.sections}>
<Router/>;
</FooContext.Provider>
)
}
}
class Router extends React.PureComponent {
render() {
return
<BrowserRouter>
<Switch>
<Route exact path="/" component={Root} />
</Switch>
</BrowserRouter>
}
}
const Root = props => <FooContext.Consumer>{sections => <SubmitProject/> }</FooContext.Consumer>;
export default App;
更新的代码V#2 App.js
import React from 'react';
import SubmitProject from './SubmitProject';
import Home from './Home';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
const FooContext = React.createContext();
class App extends React.Component {
state = {
sections:{}
};
addSection = section =>{
const sections = {...this.state.sections};
sections[`section${Date.now()}`] = section;
this.setState({
sections: sections
});
}
render() {
return (
<FooContext.Provider value={this.state.sections}>
<Router/>;
</FooContext.Provider>
)
}
}
class Router extends React.PureComponent {
render() {
return (
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/portfolio" component={Portfolio} />
</Switch>
</BrowserRouter>
)
}
}
const Portfolio = props => <FooContext.Consumer>{foo => <SubmitProject/>}</FooContext.Consumer>;
export default App;
SubmitProject.js
import React from 'react';
import PortfolioForm from './PortfolioForm';
import Section from './Section';
class SubmitProject extends React.Component {
render() {
return(
<React.Fragment>
<h1>Submit Project</h1>
<h2>Enter Project Data</h2>
<ul className="section">
{Object.keys(this.state.sections).map(key => <Section key={key} details={this.state.sections[key]}/>)}
</ul>
<PortfolioForm addSection={this.addSection} />
</React.Fragment>
)
}
}
export default SubmitProject;
建议使用状态管理器(如上下文api)或其他方法,但我想知道是否存在一种方法来重组我的App,并能够从每个组件和路由共享的顶级组件传递状态。
这种方法存在问题。
考虑到App
维护应用程序状态,有必要将其作为prop传递给<Router>
,然后路由依赖于它的组件:
class App extends React.Component {
state = { foo: true };
render() {
return <Router foo={this.state.foo}/>
}
}
const Router = props => (
const RootWithFoo = props => <Root foo={props.foo}/>;
return <BrowserRouter>
<Switch>
<Route exact path="/" component={RootWithFoo} />
...
</Switch>
</BrowserRouter>
);
这限制了组件的结构。 为了避免深入传递道具,应删除Router
组件,并应直接在App
呈现Route
:
class App extends React.Component {
state = { foo: true };
render() {
const RootWithFoo = props => <Root foo={this.state.foo}/>;
return <BrowserRouter>
<Switch>
<Route exact path="/" component={RootWithFoo} />
...
</Switch>
</BrowserRouter>
}
}
这是上下文API和状态管理库(例如Redux)解决的问题。 它们允许为使用嵌套状态的组件提供全局状态。
另一个问题是性能。 每次状态更新时,整个路由器将重新呈现。 同样,上下文API和状态管理库可以解决此问题。 如上下文API手册所述:
只要提供商的价值支柱发生变化,作为提供商的后代的所有消费者都将重新渲染。 从Provider到其后代Consumer的传播不受shouldComponentUpdate方法的限制,因此即使祖先组件退出了更新,也要对Consumer进行更新。
因此,如果上下文提供者的值更新,则无需重新渲染整个树。 无论如何,上下文使用者将被重新渲染。 由于默认情况下将重新渲染整个树,因此Provider
child(ren)应该是纯组件,以避免不必要的重新渲染。 这就是为什么最好将分离的App
和Router
组件作为首选的原因:
class App extends React.Component {
state = { foo: true };
render() {
return <FooContext.Provider value={this.state.foo}>
<Router/>;
</FooContext.Provider>
}
}
class Router extends React.PureComponent {
render() {
return <BrowserRouter>
<Switch>
<Route exact path="/" component={Root} />
...
</Switch>
</BrowserRouter>
}
}
const Root = props => <FooContext.Consumer>{foo => ...}</FooContext.Consumer>;
更新全局状态后,仅重新渲染依赖于该状态的App
和路由组件( Root
等),而不是Router
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.