1.组件数据传递问题
数据传递:A(顶级组件)-》B组件(子组件)、C组件(孙子组件)…很多组件
这样得通过props层层传递到下面的组件
还有另一种解决方法,即通过全局对象来解决,使用Provider可以解决数据层层传递和每个组件都要传props的问题;
2.props传递例子
学习react-环境&手脚架&页面&路由
在上一节的路由配置文件中,HomePage传递了name值
// Router.tsx
const routes: RouteObject[] = [{path: '/',element:<HomePage name={"test"} /> //<Navigate to='home/one' /> // 重定向},{path: 'login',element: <LoginPage name={"login"} />},// 未匹配到页面{path: '*',element: <NotFoundPage name={"notfound"} />}
]
在这一节中,创建MainPage,并在HomePage中引用
// MainMeta.tsx
export interface MainProp extends MetaProp{}export interface MainState extends MetaState{}
// MainPage.tsx
class MainPage extends Component<MainProp, MainState> {constructor(props: MainProp) {super(props);this.state = { count: 0 };}render() {const { name } = this.props; //解构赋值return <h1>Hello main page, {name}!</h1>;}}
MainPage在HomePage中引用,并用props继续给MainPage传递name值
// MainPage.tsx
class MainPage extends Component<MainProp, MainState> {constructor(props: MainProp) {super(props);this.state = { count: 0 };}render() {const { name } = this.props; //解构赋值return <h1>Hello main page, {name}!</h1>;}}
如下图props的name字段,值为test,一层层传递
3.用全局对象context
1. state共同维护context(function模式)
首先创造Global.tsx和ConfigProvider.tsx
// Global.tsx
class Global {constructor() {}count = 0;name = 'react';loading = true;
}const globalStore = new Global();
export {globalStore};
// ConfigProvider.tsx
export const configContext = React.createContext<
{ global: Global; setGlobal: React.Dispatch<React.SetStateAction<Global>>;} | null >(null);export const useConfig= ()=>useContext(configContext)interface Props{children: React.ReactNode
}
export function ConfigProvider({ children}:Props) {const [global, setGlobal] = useState(globalStore);return (<configContext.Provider value={{global, setGlobal}}>{children}</configContext.Provider>)}
在index.tsx引入ConfigProvider
// index.tsx
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);
root.render(<React.StrictMode><HashRouter><ConfigProvider><App /></ConfigProvider></HashRouter></React.StrictMode>
);
创建ActionBar.tsx,并获取Provider Global存储的值,并在点击事件里面触发改变Global存储的值
// ActionBar.tsx
const ActionBar = () => {const config = useConfig()return (<div onClick={() => {config?.setGlobal({...config.global, name:"kk"})}}><h3>{config?.global.name}-test actionbar</h3></div>);
}export default ActionBar;
在MainPage.tsx里面引用ActionBar
// MainPage.tsx
class MainPage extends Component<MainProp, MainState> {constructor(props: MainProp) {super(props);this.state = { count: 0 };}render() {const { name } = this.props; //解构赋值return(<div><ActionBar/><h1>Hello main page, {name}! </h1></div>); }}
2. state共同维护context(class 模式)
首先创建Global.tsx和ThemeProvider.tsx
// Global.tsx
export class Global {constructor() {}type = "";count = 0;name = 'react';loading = true;
}const globalStore = new Global();
export {globalStore};
// ThemeProvider.tsx
export interface ThemeContextStore{global: Global; setGlobal: React.Dispatch<React.SetStateAction<Global>>;
}
export const ThemeContext = React.createContext< ThemeContextStore | null >(null);interface Props{children: React.ReactNode
}
export function ThemeProvider({ children}:Props) {const [global, setGlobal] = useState(globalStore);return (<ThemeContext.Provider value={{global, setGlobal}}>{children}</ThemeContext.Provider>)}
在index.tsx引入ThemeProvider
// index.tsx
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);
root.render(<React.StrictMode><HashRouter><ThemeProvider><App /></ThemeProvider></HashRouter></React.StrictMode>
);
在MainPage.tsx里面用consumer使用 context
class MainPage extends Component<MainProp, MainState> {static contextType=ThemeContextconstructor(props: MainProp) {super(props);this.state = { count: 0 };}render() {const { name } = this.props; //解构赋值return(<ThemeContext.Consumer>{(test)=>(<div onClick={()=>{ test?.setGlobal({...test?.global, name:"ok"})}}>{name}={test?.global.name}</div>)}</ThemeContext.Consumer>); }}export default MainPage;
3.使用reducer 维护context
首先创建Global.tsx和Provider.tsx
// Global.tsx
export class Global {constructor() {}type = "";count = 0;name = 'react';loading = true;
}const globalStore = new Global();
export {globalStore};
// Provider.tsx
export const stores = {globalStore};
type Action = {type:'set'|'get',key:keyof Global,value:any
}type GlobalContext = {global:Globaldispatch:React.Dispatch<Action>
}export const storesContext = React.createContext<GlobalContext | null>(null);export const useGlobal = ():GlobalContext|null => React.useContext(storesContext);interface Props{children: React.ReactNode
}function globalReducer(global:Global, action:Action):Global {switch (action.type) {case 'get':{return global;}case 'set': {return {...global, [action.key]:action.value};}default: {throw Error('Unknown action: ' + action.type);}}
}export function StoresProvider({ children}:Props) {const [global, dispatch] = useReducer(globalReducer, globalStore);return (<storesContext.Provider value={{global, dispatch}}>{children}</storesContext.Provider>);}
在index.tsx引入Provider
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);
root.render(<React.StrictMode><HashRouter><StoresProvider><App /></StoresProvider></HashRouter></React.StrictMode>
);
创建TitleBar.tsx,并获取Provider Global存储的值,并在点击事件里面触发改变Global存储的值
// TitleBar.tsx
onst TitleBar = () => {const [name, setName] = useState("do");const globalContext = useGlobal ();return (<div onClick={() => {globalContext?.dispatch({type: 'set',key: "count",value:1});//setName("click")}}><h3>{globalContext?.global.count}- {name}</h3></div>);
}export default TitleBar;
在MainPage.tsx里面引入Titlebar
// MainPage.tsx
class MainPage extends Component<MainProp, MainState> {constructor(props: MainProp) {super(props);this.state = { count: 0 };}render() {const { name } = this.props; //解构赋值return(<div><TitleBar/><h1>Hello main page, {name}! </h1></div>); }