创建项目:

创建react项目:

npx create-react-app demo-app            //demo-app为项目名称

运行项目:

npm start 

其他(安装npx命令):

npm install -g npx

初步工作:

1.删除src下的其他文件,只留下app.jsx,app.css,index.js,index.css。

2.app.jsx相当于vue的app.vue,index.js相当于vue的main.js。

3.新建文件的时候尽量以vue目录的结构为标准,组件就放在components目录,页面放在views目录,redux放在store目录,路由放在router目录。

4.定义组件的名字首字母大写,组件后缀.jsx。

快速生成代码:

安装插件:

ES7 React/Redux/GraphQL/React-Native snippets

新建文件后,输入rafc或rafce可以快速生成react模板代码(用户片段)。

相关知识:

1.react官方已经推荐使用函数式组件,可以暂时不学习类组件;目前所有的新项目都是采用全部函数式组件实现,只有一个老项目需要迭代更新的才使用的是类组件。

react的注意事项:

1.不要在jsx语法中使用 if - else,可以使用三目运算、或运算、与运算;jsx语法只支持表达式,不支持js语句。

2.不要在jsx语法中使用 for 循环, 使用 map 循环;

3.添加状态必须在构造方法,添加构造方法必须执行super();

4.组件必须导入React;   

常用hooks函数(记一下最好):

useState:状态钩子。声明响应式数据

useEffect:副作用钩子。生命周期,相当于vue的mounted。

useReducer:Action 钩子。状态管理钩子useRef

useLocation:接收页面跳转的参数。

useHistory:跳转页面,并可以传递参数。(页面跳转推荐这种方式)

一、基本方法。

基本知识:

1.react每一个组件都是一个函数。

2.jsx语法:在js当中嵌套html,如果要写html代码,必须return(html),必须有一个跟节点<div>嵌套,可以写成<></>。

基础语法:

1.定义数据:在react引入useState,useState是一个函数,里面传入初始化的数据,返回一个数组,数组的第一项是数据本身,第二项是改变数据的方法,显示数据用:{数据名}。

2.绑定事件:都是on开头。

App.css:

.app-active{
    color:red;
}
.app-box{
    height:20px;
    border:1px solid red;
    margin-bottom:20px;
}

app.jsx:

import React,{useState,useEffect,useRef} from 'react'//使用jsx语法,必须引入React。
import './App.css'

const App=()=>{
    let [name,setName]=useState('jack')//创建数据,name为变量,setName修改这个变量的方法,jack为初始化这个变量的值。useState定义的方式代表声明响应式数据。
    let [age,setAge]=useState(10)
    let [activeIndex,setActiveIndex]=useState(-1)
    let [arr,setArr]=useState([
    {name:'香蕉'},{name:'橘子'}
    ])
    let update=()=>{
        setName('tom')
        setAge(20)
    }
    //点击事件调用的方法,并接收传递过来的参数
    let clickItem=(item,index)=>{
      setActiveIndex(index)
      console.log(item,index)
    }
    //等于vue的mounted
    useEffect(()=>{
      //发请求
      //数据初始化
      console.log('effect');
      //组件销毁,如果不做操作可以不写
      return ()=>{
        //清除定时器
      }
    },[])
    return (
    <div>
        <div>{name}---{age}</div>{/*{name}:渲染数据*/}
        <div>
            <button onClick={update}>更新数据</button>{/*onClick={update}:绑定事件的方法。*/}
        </div>
        <div style={{height:'20px',padding:'10px 20px'}}>样式</div>
        {/*不带单位默认px,多个样式要用引号*/}
        {
            arr.map((item,index)=>{
              return (
              <div key={index} onclick={()=>clickItem(item,index)} className={`app-box ${activeIndex === index?'app-active':''}`}>
                {/*return中不能写if,只能写三目表达式,其他语法也不行。可以在return上面进行if,return不同的结果。*/}
                {/*传参数只能通过()=>clickItem(item,index)箭头函数的形式。*/}
                {item.name}
              </div>
              )
            })
        }
    </div>
    )
}

export default App

二、组件传参数,获取dom元素,获取子组件实例。

以下省略了部分代码:

app.jsx:

import React,{useState,useEffect,useRef,useRef} from 'react'

let dv=useRef(null);

let child=useRef(null);

let send=(val)=>{

    console.log('子组件传过来的数据:',val);

    console.log('获取的dom:',dv.current);

    console.log('获取子组件的所有节点:',child.current);//跟上一个一模一样。无法调用子组件的方法。

}

return (

    <>

        <Child ref={child} name={name} send={send}></Child>

        <div ref={dv}>123</div>

    </>

)

child.jsx:

import React,{useState,forwardRef} from 'react'

const Child=(props,ref)=>{

    let [msg]=useState('子组件的数据');

    let send=()=>{

      props.send(msg);//调用父组件传递过来的方法,并将值传过去。也就是回调函数的形式。

    }

    return (

      <div ref={ref}>

        <div>父组件传递过来的数据:{props.name}</div>

        <div>

        <button onClick={send}>传值给父组件</button>

        </div>

      </div>

    )

}

export default forwardRef(Child);

三、路由守卫。

安装路由守卫插件:

npm i -S react-router-dom

新建目录文件src下:router/index.js。//与vue相似。router/index.js:

//配置路由
import Home from '../views/home/home'//最好用'@/views/home/home
import Login from '../views/login/login'
import NotFound from '../views/404/404'

//有权限
export const authRoutes=[
{
    path:'/',
    component:Home,
    exact:true,//是否精准匹配,为false就会把所有的匹配了。
    meta:{
      title:'首页'
    }
}
]
//没权限
export const commomRoutes=[
{
    path:'/login',
    component:Login,
    exact:true,//是否精准匹配,为false就会把所有的匹配了。
    meta:{
      title:'登录'
    }
},
{
    path:'/404',
    component:NotFound,
    exact:true,//是否精准匹配,为false就会把所有的匹配了。
    meta:{
      title:'404'
    }
}
]
//export default:导出一个,export:导出多个。

app.jsx:

import {BrowserRouter,Switch,Router,Redirect} from 'react-router-dom'
const App=()=>{
    return (
      <BrowserRouter>
        <Switch>
          {
            //没权限放前面
            commonRoutes.map(item=>{
              return(
                <Route key={item.path} path={item.path} 
        component={item.component exact={item.exact}    //不干任何事情,不能跟render同时出现。
        render={(props)=>{    //需要做其他事情,比如设置标题,不能跟上面的component偶同事出现
          document.title=item.meta.title;
          return (
            <item.component {...props}/>    //单双标签都可以
          )
        }}
                 />
              );
            })
          }
          {
            //有权限
            authRoutes.map(item=>{
              return(
                <Route key={item.path} path={item.path}
         component={item.component exact={item.exact}     //不干任何事情,不能跟render同时出现。
        render={(props)=>{    //需要做其他事情,比如设置标题,不能跟上面的component偶同事出现
          document.title=item.meta.title;
          //路由守卫,判断是否登录
          if(!localStorage.getItem('token')){
            return (
              <Redirect to='/login' />
            )
          }
          return (
            <item.component {...props} />    //单双标签都可以
          )
        }}
                 />
              );
            })
          }
          <Redirect to='/404' />
        </Switch>
      </BrowserRouter>
    )
}

login.jsx:     //跳转路由的方法


import React from 'react'
import { useHistory } from 'react-router-dom'
const Login=(props)=>{
    let history=useHistory();
    let login=()=>{
      //跳转路由方式一props。很老旧
      props.history.push('/');    
      //调试方式二。hook函数的方式。最新版本有可能会报错。
      history.push('/');    //不传参数,'/'是home页面
      history.push('/',{name:'jack'});    //跳转路由传参数
    }
    return (
      <div>
        <button onClick={login}>登录</button>
      </div>
    )
}
export default Login

Home.jsx,Login.jsx,NotFound.jsx对应着主页,登录页和404页面,里面的内容我就不写了。

说明:

1.props跳路由的方式只有路由组件可以使用,首先要用<item.component {...props} />传递路由信息,然后调用当中的props.history.push跳转路由。

2.没有注册的子组件是不能使用props.history.push这种方式跳转路由的,因为他获取不到路由的信息。

home.jsx:        //接收路由跳转参数

import React from 'react'
import { useLocation } from 'react-router-dom'
const Home=(props)=>{
    let location=useLocation();
    console.log('传递的参数:',location)
    return (
      <div>Home
      </div>
    )
}
export default Home;

四、公共路由和redux状态管理。

安装redux状态管理:

npm i -S redux react-redux redux-thunk

src/index.js:

import store from '@/store'
import {Provider} from 'react-redux'
ReactDOM.render(
  <Provider store={store}>
      <App />
  </Provider>,
  document.getElementById('root')
)

store/index.js:

import {createStore,combineReducers} from 'redux'    //combineReducers等同于vue的mutation
import thunk from 'redux-thunk'    //发请求
import user from './reducers/user/user'    //引入模块

const store=createStore(combineReducers({
    user        //多个模块以空格隔开
}),applyMiddleware(thunk));
export default store

store/reducers/user.js:        //相当于mutation

let initState={
    menus:[],
    users:[]
}
//active是一个 对象,一个是type,一个是data。
export default function userReducer(state=initState,action){
    switch(action.type){
      case 'login':
        return {
          ...state,
        }
      case 'getMenus':
        return {
          ...state,
          menus:action.data
        }
      case 'getUsers':
        return {
          ...state,
          users:action.data
        }
      default:
        return {
          ...state
        }
    }
}

src/http/index.js:        //封装请求

安装axios:

npm i axios -S

import  axios from 'axios'
const http=axios.create({
    timeout:10000,
    baseURL:'/api'
})
http.interceptors.request.use(config=>{
    let token=localStorage.getItem('token');
    if(token){
      config.headers.auth=token;
    }
    return config;
});
http.interceptors.response.use(res=>{
    return res.data;
});
export default http;

src/http/api.js:        //封装请求
import api from './api.js'
export default {
    login({username,password}){
      return http.post('/login',{username,password});
    },
    getMenu(){
      return http.post('/getMenu',);
    }
}

store/actions/user/index:    //相当于vue的action

import api from '@/http/api.js'
//导出多个方法
export function login(params){
    //发请求
    return async (dispatch)=>{
      let res=await api.login(params);
      if(res.meta.status===200){
        localStorage.setItem('token',res.data.token);
        localStorage.setItem('user',JSON.stringify(res.data));
        window.location.pathname='/'    //跳路由的方式,其他不行。
        //提交reducers。等同于调用vue的mutation方法修改state的值。
        dispatch({
          type:'login'
        })
      }
    }
}
export function getMenus(params){
    //发请求
    return async (dispatch)=>{
      let res=await api.getMenus(params);
      if(res.meta.status===200){
        //提交reducers。等同于调用vue的mutation方法修改state的值。
        dispatch({
          type:'login',
          data:res.data
        })
      }
    }
}

login.jsx:        //如何提交reducers(mutation)

import {login} from '@/store/actions/user/user'
imort {useDispatch} from 'react-redux'
const Login=(props)=>{
    let dispatch=useDispatch()
    let loginBtn=(val)=>{
      //调用action中的方法
      dispatch(login({
        username:val.username,
        password:val,password
      }));
      console.log('点击登录获取到的账号密码:',val)
    }
    //省略部分代码
}

后端请求的代理配置(相当于vue的vue.config.js):

安装http-proxy-middleware:

$ npm install --save-dev http-proxy-middleware

src/setupProxy.js:        //跟vue的路径结构是存在区别的,注意哈

const {createProxyMiddleware} = require('http-proxy-middleware')
module.exports=function(app){
    app.use(createProxyMiddleware('/api',{
      ws:false,
      target:'http://192.177.2.99/api/private/v1/',
      changeOrigin:true,
      pathRewrite:{
        '^/api':''
      }
    }))
}

Logo

前往低代码交流专区

更多推荐