一个前端,爱跑步、爱吉他、爱做饭、爱生活、爱编程、爱南芳姑娘,爱我所爱。世间最温暖又无价的是阳光、空气与爱,愿它们能带你去更远的地方。

  • 文章
  • 心情
  • 照片墙
  • 留言板
  • 工具
  • 友链
  • biaoblog

    专注web开发技术分享

    react hook+ts+rouerV6 dev notes

    技术 166 2021-12-06 13:22

    1.React useHistory 更新为useNavigate如何传值

    路由组件如何传值

    1.组件跳转并传值

    (1)导入

    import { useNavigate } from ‘react-router-dom’;
    

    (2)使用

    const navigate = useNavigate();
    

    点击事件中使用

     组件“/machine”为已经定义好的路由,state负责传值state:{参数:值}

        navigate('/machine', {
          state: {
            from: '1'
          }
        })
    

    (3)获取值

    导入import { useLocation } from ‘react-router-dom’;
    

    使用

    let location = useLocation();
    let server_id = location.state;
    
    

    2.封装公共dialog的小技巧(children props使用)

    首先独立封装一个antd的dialog

    import React, { useState } from 'react';
    import { Modal, Button } from 'antd';
    import CommonStyle from '../../../resources/styles/common.module.css'
    const Dialog = (props: any) => {
      console.log(props)
    
      const { children } = props
      const [isModalVisible, setIsModalVisible] = useState(true);
    
      const showModal = () => {
        setIsModalVisible(true);
      };
    
      const handleOk = () => {
        setIsModalVisible(false);
      };
    
      const handleCancel = () => {
        setIsModalVisible(false);
      };
      return (
    
        <>
          <Modal footer={null} visible={isModalVisible} onOk={handleOk} onCancel={handleCancel} closable={false}>
            {children}
            {/* <div className={CommonStyle.modalNav}>
              <span className={`${CommonStyle.modalNavTitle}`}>
                <img className={`${CommonStyle.modalNaviImage}`} src="https://pickkiwi.s3.amazonaws.com/upload/ly1sYz9aM986CwIOOCQ6Kwxx2vSxJK5eOia16D8x6nLO7cWTDTk7jKSwCl3bj-Ku2AGKSd7l" alt="" />
                Request Product
              </span>
              <span className={`${CommonStyle.modalNavClose}`}><span className={`iconfont icon-exit ${CommonStyle.modalNavCloseIcon}`}></span></span>
            </div> */}
    
          </Modal>
        </>
      )
    }
    
    export default Dialog
    

    然后在外面进行引用:

          <Dialog>
            <div className={CommonStyle.modalNav}>
              <span className={`${CommonStyle.modalNavTitle}`}>
                <img className={`${CommonStyle.modalNaviImage}`} src="https://pickkiwi.s3.amazonaws.com/upload/ly1sYz9aM986CwIOOCQ6Kwxx2vSxJK5eOia16D8x6nLO7cWTDTk7jKSwCl3bj-Ku2AGKSd7l" alt="" />
                Request Product
              </span>
              <span className={`${CommonStyle.modalNavClose}`}><span className={`iconfont icon-exit ${CommonStyle.modalNavCloseIcon}`}></span></span>
            </div>
          </Dialog>
    

    组件包裹的部分,

    可以使用this.props.children来获取并显示

    const { children } = props
    <Modal footer={null} visible={isModalVisible} onOk={handleOk} onCancel={handleCancel} closable={false}>
            {children}
     </Modal>
    

    3.使用antd-form的内嵌组件(包括验证)

    我们的想要的效果图:

    代码:

       <Form
            name="basic"
            layout="vertical"
            onFinish={onFinish}
            onFinishFailed={onFinishFailed}
          >
            <Form.Item
              label="Desired Cost"
            >
              <Input.Group compact>
                <Form.Item
                  name={['DesiredCost', 'cost']}
                  noStyle
                  rules={[{ required: true, message: 'desiredCost is required' }]}
                >
                  <Input style={{ width: 365 }} placeholder="$10.00" />
                </Form.Item>
    
                <Form.Item
                  name={['DesiredCost', 'currency']}
                  noStyle
                  rules={[{ required: true, message: 'currency is required' }]}
                >
                  <Select style={{ width: 100, marginLeft: 2 }}>
                    {currencyOpts.map((opt: any, index: any) => <Option key={index} value={opt.value}>{opt.label}</Option>)}
                  </Select>
                </Form.Item>
    
              </Input.Group>
    
            </Form.Item>
          </Form>
    

    其实就是Form.Item里面套一个Input.group

    然后再套Form.item就可以了,验证独自给form.item加上rules即可

    参考文档:https://ant.design/components/form-cn/#header

    4.重置antd-form

    创建一个ref

     const formRef: any = React.createRef()
    

    挂载到form上(我的组件是通过子组件传值过去的)

    传递给子组件

     <RequestForm formRef={formRef} product={product} closeModal={closeModal} />
    

    挂载

         <Form
            ref={formRef}
          >
    

    关闭dialog时重置表单(父组件方法)

     const closeModal = () => {
        console.log(formRef)
        formRef.current.resetFields()
        setVisible(false)
      }
    

    参考地址:https://blog.csdn.net/wsh2467991332/article/details/113850917

    5.hook的useEffect 实现class的componentWillReceiveProps

      useEffect(() => {
        _getRequests()
      }, [filterArgs])
    

    filterArgs就是我们要传递的Props,如果这个传递的值更新了 就会触发UseEffect

    小技巧:

    一个hooks里面可以写多个useEffect

    来处理不同的方法

      useEffect(() => {
        _getRecentRequests()
      }, [])
    
      useEffect(() => {
        _getRequests()
      }, [filterArgs])
    

    6.antd的上传组件 实现自定义上传(类似于element的自定义上传文件)

    关键api:customRequest

    上代码:

    首先是elementUI的自定义上传代码(关注:http-request):

    组件部分:

           <el-upload
                action
                list-type="picture-card"
                :on-preview="handlePictureCardPreview"
                :on-remove="handleRemove"
                :http-request="setBase"
                accept=".jpg, .jpeg, .png, .gif, .JPG, .JPEG, .GIF"
                :limit="1"
              >
                <i class="el-icon-plus"></i>
              </el-upload>
    

    方法:

        setBase(e) {
          //   el-upload上传的图片是blob对象 把它转为为base64再进行上传 e.file是blob对象
          let params = new FormData();
          params.append("file", e.file);
          upload(params).then(res => {
            if (res.data) {
              this.title = e.file.name;
              this.IMGArr.push({
                name: res.data.filename,
                uid: e.file.uid
              });
            }
          });
        },
    

    结束 就这么简单

    然后是antd的自定义上传设置

    首先是组件:(关注customRequest部分)

           <Upload
              listType="picture-card"
              fileList={fileList}
              customRequest={this.handleChange}
            >
              <div className={Styles.uploadBtnHide} id="uploadBtnHide">Add Images</div>
            </Upload>
    

    然后是方法拿到文件,然后就传递吧 下课!

     handleChange = (event: any) => {
        console.log(event.file)
      }
    

    完整的react+antd组件上传demo

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    
        <link
          rel="stylesheet"
          href="https://cdnjs.cloudflare.com/ajax/libs/antd/4.18.8/antd.min.css
        "
        />
        <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
        <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/antd/4.18.8/antd.min.js"></script>
    
        <style>
          #uploadBtn {
            display: none;
          }
        </style>
      </head>
      <body>
        <div id="root"></div>
      </body>
      <style></style>
      <script type="text/babel">
        class App extends React.Component {
          constructor(props) {
            super(props);
            this.state = {
              testVal: "123",
              fileList: [],
            };
          }
    
          render() {
            console.log(this);
            let { fileList } = this.state;
            return (
              <h1>
                <div id="uploadBtn">
                  <antd.Upload
                    listType="picture-card"
                    customRequest={this.handleChange}
                  >
                    <antd.Button id="clickUploads"></antd.Button>
                  </antd.Upload>
                </div>
                <antd.Button onClick={this.clickUpload}>
                  Click to Upload
                </antd.Button>
                文件列表:
                <div>
                  {fileList.map((item, index) => (
                    <antd.Image width={200} key={index} src={item} />
                  ))}
                </div>
              </h1>
            );
          }
    
          handleChange = (event) => {
            console.log(event.file);
            let { fileList } = this.state;
            const fd = new FormData();
            fd.append("file", event.file);
            fetch("http://biaoblog.cn:3000/blogData/upload", {
              headers: {
                authorization:
                  "Bearer xxx",
              },
              body: fd,
              method: "POST",
            })
              .then((res) => res.json())
              .then((res) => {
                console.log(res.filename);
                console.log(fileList);
                let newFileList = fileList;
                newFileList.push(res.filename);
                this.setState({
                  fileList: newFileList,
                });
    
                console.log();
              });
          };
    
          clickUpload = () => {
            document.querySelector("#clickUploads").click();
          };
        }
        ReactDOM.render(<App />, document.getElementById("root"));
      </script>
    </html>
    

    7.antd-form中自动获取checkbox组件的值

    需要在chekbox中添加一个属性:

    valuePropName="checked"

          <Form
            ref={formRef}
            name="basic"
            layout="vertical"
            onFinish={onFinish}
            onFinishFailed={onFinishFailed}
          >
           <Form.Item
              name="accept_similar"
              valuePropName="checked"
            >
              <Checkbox>Accept similar products</Checkbox>
            </Form.Item>
    <Form>
    

    8.react-redux 持久化 仓库配置(包含thunk,history)

    import { createStore, applyMiddleware, compose } from "redux";
    import thunk from "redux-thunk";
    import { persistStore, persistReducer } from "redux-persist";
    import storage from "redux-persist/lib/storage";
    import { routerMiddleware } from "connected-react-router";
    //引入汇总之后的reducer
    import createRootReducer from "./reducers";
    import { createBrowserHistory as createHistory } from "history";
    export const history = createHistory();
    let composeEnhancer = compose;
    //在localStorge中生成key为root的值
    const persistConfig = {
      key: "root",
      storage,
    };
    
    if (process.env.NODE_ENV !== "production") {
      composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    }
    const router = routerMiddleware(history);
    const myPersistReducer = persistReducer(
      persistConfig,
      createRootReducer(history)
    );
    
    
    const store = createStore(
      myPersistReducer,
      composeEnhancer(applyMiddleware(thunk, router))
    );
    
    
    export const persistor = persistStore(store);
    
    
    export default store; //暴露出去
    
    
    

    然后在App.js中进行引入

    import { Provider } from 'react-redux'
    import { PersistGate } from 'redux-persist/es/integration/react'
    import store, { persistor } from './redux/store/index'
    import AppRouter from './router'
    function App() {
      return (
        <Provider store={store}>
          <PersistGate loading={null} persistor={persistor}>
            <AppRouter />
          </PersistGate>
        </Provider>
      )
    }
    
    export default App
    

    然后往仓库存储一个数据,刷新,发现持久化Ok了,下课

    9.在react-hook中获取到redux仓库中的值(封装了thunk)

    跟class的写法一样(前提是封装thunk)

    先引用:

    import { connect } from 'react-redux'
    

    然后使用:

    function mapStateToProps(state: any) {
      return {
        userInfo: state.app.currentUser.user
      }
    }
    
    export default connect(mapStateToProps)(AccountIndex);
    

    然后在组件中获取:

    const AccountIndex = (props: any) => {
      console.log(props.userInfo) // props.userInfo就是仓库里面的数据
      return <Container>
    
      </Container>
    }
    

    结束!

    10.一个Input的动态样式,可以参考

    unclick:

    click:

    非常简单,想复杂了


    11.antd-form 自定义校验

    需求就是我们的验证码组件需要校验

    可以用到form的自定义检验(就是拿到form的value和验证码 进行对比 然后抛错,挺方便)

        <Form.Item
                name={["user", "code"]}
                label="验证码"
                rules={[
                  { required: true },
                  ({ getFieldValue }) => ({
                    validator(_, value) {
                      console.log(SIdentifyRef);
                      if (value == SIdentifyRef.current.state.code) {
                        return Promise.resolve();
                      }
                      return Promise.reject(new Error("验证码错误"));
                    },
                  }),
                ]}
                style={{ width: 300 }}
              >
                <Row gutter={16}>
                  <Col className="gutter-row" span={18}>
                    <Input style={{ width: 200 }} />
                  </Col>
                  <Col className="gutter-row" offset={1} span={2}>
                    <SIdentify ref={SIdentifyRef} />
                  </Col>
                </Row>
              </Form.Item>
    

    12.一个href的动画css效果


    html

        <a href="11111">哈哈哈哈</a>
    

    css

        a {
          text-decoration: none;
          border-bottom: 1px solid;
          border-bottom-color: #00000026;
          position: relative;
          display: inline-block;
          color: black;
        }
    
        a:after {
          content: "";
          position: absolute;
          bottom: -2px;
          left: 0;
          width: 0%;
          border-bottom: 2px solid currentColor;
          transition: width 0.5s ease;
        }
        a:hover:after {
          width: 100%;
        }
    

    13.使用useMediaQuery来判断pc和mobile

    import useMediaQuery from '@/hooks/useMediaQuery'
    const Login = () => {
      const isMobile = useMediaQuery('(max-width: 800px)')
      return (
        <Container className={Styles.loginContainer}>
          <Header className={Styles.loginHeader} showButtons={false} />
          <LoginForm />
          {
            !isMobile && <Footer />
          }
        </Container>
      );
    }
    

    14.使用lodash来判断数据是否存在(避免一些报错异常)

    import _ from 'lodash'
    const ProductItem = (props: any) => {
      const { product, onRequest } = props
    
      return (
        <div className={Styles.similarPrdItem}>
          {!_.isEmpty(product.images) && (
           <YourCom/>
      )
    }
    

    15.antd form自定义表单验证

     <Form.Item
      name={["applyLink", "code"]}
      style={{ width: 200 }}
      rules={[
        ({ getFieldValue }) => ({
          validator(_, value) {
            // console.log(SIdentifyRef);
            if (value == SIdentifyRef.current.state.code) {
              return Promise.resolve();
            }
            return Promise.reject(new Error("验证码错误"));
          },
        }),
      ]}
    >
    

    文章评论

    评论列表(0