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=ThemeContext
constructor(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:Global
dispatch: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>
);
}