react--快速入门

React 应用程序是由 组件 组成的。一个组件是 UI(用户界面)的一部分,它拥有自己的逻辑和外观。组件可以小到一个按钮,也可以大到整个页面。

  • React 组件是返回标签的 JavaScript 函数:
    function MyButton() {
      return (
        <button>I'm a button</button>
      );
    }
    
    注意:React 组件必须以大写字母开头,而 HTML 标签则必须是小写字母

使用 JSX 编写标签

  • 上面所使用的标签语法被称为 JSX。是可选的,但大多数 React 项目会使用 JSX,主要是它很方便。所有推荐的本地开发工具 都开箱即用地支持 JSX。

  • JSX 比 HTML 更加严格。必须闭合标签,如 < br />。组件也不能返回多个 JSX 标签。必须将它们包裹到一个共享的父级中,比如 < div>…< /div> 或使用空的 <>…</> 包裹:

添加样式

  • 在 React 中,可以使用 className 来指定一个 CSS 的 class。与 HTML 的 class 属性的工作方式相同:

    <img className="avatar" />
    
  • 然后,在一个单独的 CSS 文件中编写 CSS 规则:

    /* In your CSS */
    .avatar {
      border-radius: 50%;
    }
    

显示数据

  • JSX 会把标签放到 JavaScript 中。而大括号里的内容会 “回到” JavaScript 中,这样就可以从代码中嵌入一些变量并展示给用户。例如,将显示 user.name:

    return (
      <h1>
        {user.name}
      </h1>
    );
    
  • 还可以将 JSX 属性 “转义到 JavaScript”,但必须使用大括号 而非 引号。例如,className=“avatar” 是将 “avatar” 字符串传递给 className,作为 CSS 的 class。但 src={user.imageUrl} 会读取 JavaScript 的 user.imageUrl 变量,然后将该值作为 src 属性传递:

    return (
      <img
        className="avatar"
        src={user.imageUrl}
      />
    );
    
  • 可以把更为复杂的表达式放入 JSX 的大括号内,例如 字符串拼接:

    const user = {
      name: 'Hedy Lamarr',
      imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
      imageSize: 90,
    };
    
    export default function Profile() {
      return (
        <>
          <h1>{user.name}</h1>
          <img
            className="avatar"
            src={user.imageUrl}
            alt={'Photo of ' + user.name}
            style={{
              width: user.imageSize,
              height: user.imageSize
            }}
          />
        </>
      );
    }
    
  • 在上面示例中,style={{}} 并不是一个特殊的语法,而是 style={ } JSX 大括号内的一个普通 {} 对象。当样式依赖于 JavaScript 变量时,可以使用 style 属性。

条件渲染

  • React 没有特殊的语法来编写条件语句,因此使用的是普通的 JavaScript 代码。例如使用 if 语句根据条件引入 JSX:

    let content;
    if (isLoggedIn) {
      content = <AdminPanel />;
    } else {
      content = <LoginForm />;
    }
    return (
      <div>
        {content}
      </div>
    );
    
  • 如果喜欢更为紧凑的代码,可以使用 条件 ? 运算符。与 if 不同的是,它工作于 JSX 内部:

    <div>
      {isLoggedIn ? (
        <AdminPanel />
      ) : (
        <LoginForm />
      )}
    </div>
    
  • 当不需要 else 分支时,还可以使用 逻辑 && 语法:

    <div>
      {isLoggedIn && <AdminPanel />}
    </div>
    
  • 所有这些方法也适用于有条件地指定属性。

渲染列表

  • 依赖 JavaScript 的特性,例如 for 循环 和 array 的 map() 函数 来渲染组件列表。

  • 假设有一个产品数组:

    const products = [
      { title: 'Cabbage', id: 1 },
      { title: 'Garlic', id: 2 },
      { title: 'Apple', id: 3 },
    ];
    
  • 在组件中,使用 map() 函数将这个数组转换为 < li> 标签构成的列表:

    const listItems = products.map(product =>
      <li key={product.id}>
        {product.title}
      </li>
    );
    
    return (
      <ul>{listItems}</ul>
    );
    

    注意, < li> 有一个 key 属性。对于列表中的每一个元素,都应该传递一个字符串或者数字给 key,用于在其兄弟节点中唯一标识该元素。通常 key 来自后端返回的数据,比如数据库中的 ID。如果在后续插入、删除或重新排序这些项目,React 将依靠提供的 key 来思考发生了什么。

    const products = [
      { title: 'Cabbage', isFruit: false, id: 1 },
      { title: 'Garlic', isFruit: false, id: 2 },
      { title: 'Apple', isFruit: true, id: 3 },
    ];
    
    export default function ShoppingList() {
      const listItems = products.map(product =>
        <li
          key={product.id}
          style={{
            color: product.isFruit ? 'magenta' : 'darkgreen'
          }}
        >
          {product.title}
        </li>
      );
    
      return (
        <ul>{listItems}</ul>
      );
    }
    

响应事件

  • 可以通过在组件中声明 事件处理 函数来响应事件:

    function MyButton() {
      function handleClick() {
        alert('You clicked me!');
      }
    
      return (
        <button onClick={handleClick}>
          Click me
        </button>
      );
    }
    

    注意,onClick={handleClick} 的结尾没有小括号!不要 调用 事件处理函数:只需 把函数传递给事件 即可。当用户点击按钮时 React 会调用传递的事件处理函数。

更新界面

  • 通常希望组件 “记住” 一些信息并展示出来,比如一个按钮被点击的次数。要做到这一点,需要在组件中添加 state。

  • 首先,从 React 引入 useState:

    import { useState } from 'react';
    
  • 在组件中声明一个 state 变量:

    function MyButton() {
      const [count, setCount] = useState(0);
      // ...
    
  • 从 useState 中获得两样东西:当前的 state(count),以及用于更新它的函数(setCount)。可以给它们起任何名字,但按照惯例会像 [something, setSomething] 这样命名。

  • 第一次显示按钮时,count 的值为 0,因为把 0 传给了 useState()。当想改变 state 时,调用 setCount() 并将新的值传递给它。点击该按钮计数器将递增:

    function MyButton() {
      const [count, setCount] = useState(0);
    
      function handleClick() {
        setCount(count + 1);
      }
    
      return (
        <button onClick={handleClick}>
          Clicked {count} times
        </button>
      );
    }
    
  • React 将再次调用组件函数。第一次 count 变成 1。接着点击会变成 2。继续点击会逐步递增。

  • 如果多次渲染同一个组件,每个组件都会拥有自己的 state。可以尝试点击不同的按钮:

    import { useState } from 'react';
    
    export default function MyApp() {
      return (
        <div>
          <h1>Counters that update separately</h1>
          <MyButton />
          <MyButton />
        </div>
      );
    }
    
    function MyButton() {
      const [count, setCount] = useState(0);
    
      function handleClick() {
        setCount(count + 1);
      }
    
      return (
        <button onClick={handleClick}>
          Clicked {count} times
        </button>
      );
    }
    
  • 注意,每个按钮会 “记住” 自己的 count,而不影响其他按钮。

使用 Hook

  • 以 use 开头的函数被称为 Hook。useState 是 React 提供的一个内置 Hook。可以在 React API 中找到其他内置的 Hook。也可以通过组合现有的 Hook 来编写属于自己的 Hook。

  • Hook 比普通函数更为严格。只能在组件(或其他 Hook)的 顶层 调用 Hook。如果想在一个条件或循环中使用 useState,需要提取一个新的组件并在组件内部使用它。

组件间共享数据

1. 父组件向子组件传递数据(单向数据流)

这是最基础的组件间数据传递方式,通过 props 实现。父组件可以将自身的数据作为属性传递给子组件,子组件接收并使用这些数据。

  • 示例代码
    // 父组件
    import React from 'react';
    import ChildComponent from './ChildComponent';
    
    const ParentComponent = () => {
        const sharedData = "Hello from parent!";
        return (
            <div>
                <ChildComponent data={sharedData} />
            </div>
        );
    };
    
    export default ParentComponent;
    
    // 子组件
    import React from 'react';
    
    const ChildComponent = (props) => {
        return (
            <div>
                <p>{props.data}</p>
            </div>
        );
    };
    
    export default ChildComponent;
    
2. 子组件向父组件传递数据

子组件向父组件传递数据通常通过回调函数实现。父组件将一个函数作为 prop 传递给子组件,子组件在需要的时候调用这个函数并传递数据。

  • 示例代码
    // 父组件
    import React, { useState } from 'react';
    import ChildComponent from './ChildComponent';
    
    const ParentComponent = () => {
        const [receivedData, setReceivedData] = useState('');
    
        const handleDataFromChild = (data) => {
            setReceivedData(data);
        };
    
        return (
            <div>
                <ChildComponent onSendData={handleDataFromChild} />
                <p>Received from child: {receivedData}</p>
            </div>
        );
    };
    
    export default ParentComponent;
    
    // 子组件
    import React from 'react';
    
    const ChildComponent = (props) => {
        const sendDataToParent = () => {
            const data = "Hello from child!";
            props.onSendData(data);
        };
    
        return (
            <div>
                <button onClick={sendDataToParent}>Send data to parent</button>
            </div>
        );
    };
    
    export default ChildComponent;
    
3. 跨级组件(祖先组件与后代组件)传递数据

如果组件层级较深,使用 props 层层传递数据会变得繁琐,此时可以使用 React 的 Context API。Context 提供了一种在组件之间共享数据的方式,而不必显式地通过组件树逐层传递 props。

  • 示例代码
    // 创建一个 Context
    import React, { createContext, useContext, useState } from 'react';
    
    const MyContext = createContext();
    
    // 祖先组件
    const AncestorComponent = () => {
        const [sharedData, setSharedData] = useState('Shared data from ancestor');
    
        return (
            <MyContext.Provider value={{ sharedData, setSharedData }}>
                <DescendantComponent />
            </MyContext.Provider>
        );
    };
    
    // 后代组件
    const DescendantComponent = () => {
        const { sharedData } = useContext(MyContext);
    
        return (
            <div>
                <p>{sharedData}</p>
            </div>
        );
    };
    
    export default AncestorComponent;
    
4. 非嵌套组件间共享数据

对于非嵌套关系的组件间共享数据,可以使用状态管理库,如 Redux、MobX 或 React 的 useReducer 结合 Context。这里以 Redux 为例简单说明:

  • 安装 Redux 和 React-Redux

    npm install redux react-redux
    
  • 示例代码:

    // actions.js
    export const updateData = (newData) => {
        return {
            type: 'UPDATE_DATA',
            payload: newData
        };
    };
    
    // reducer.js
    const initialState = {
        sharedData: ''
    };
    
    const rootReducer = (state = initialState, action) => {
        switch (action.type) {
            case 'UPDATE_DATA':
                return {
                    ...state,
                    sharedData: action.payload
                };
            default:
                return state;
        }
    };
    
    export default rootReducer;
    
    // store.js
    import { createStore } from 'redux';
    import rootReducer from './reducer';
    
    const store = createStore(rootReducer);
    
    export default store;
    
    // 组件 A
    import React from 'react';
    import { useDispatch } from 'react-redux';
    import { updateData } from './actions';
    
    const ComponentA = () => {
        const dispatch = useDispatch();
    
        const handleUpdateData = () => {
            dispatch(updateData('New shared data'));
        };
    
        return (
            <div>
                <button onClick={handleUpdateData}>Update shared data</button>
            </div>
        );
    };
    
    // 组件 B
    import React from 'react';
    import { useSelector } from 'react-redux';
    
    const ComponentB = () => {
        const sharedData = useSelector((state) => state.sharedData);
    
        return (
            <div>
                <p>{sharedData}</p>
            </div>
        );
    };
    
    // 根组件
    import React from 'react';
    import { Provider } from 'react-redux';
    import store from './store';
    import ComponentA from './ComponentA';
    import ComponentB from './ComponentB';
    
    const App = () => {
        return (
            <Provider store={store}>
                <ComponentA />
                <ComponentB />
            </Provider>
        );
    };
    
    export default App;
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值