零基础React + TypeScript 教程

环境配置

TypeScript 复制代码
npm create vite@latest my-app -- --template react-ts
npm install react-router-dom
npm run dev

第1章:React核心概念与JSX

1.1 什么是React?

React是构建用户界面的JavaScript库,采用组件化开发模式。

1.2 基础组件示例

TypeScript 复制代码
import React, { useState } from "react";
​
interface SonProps {
  name: string;
}
​
// 函数组件与Props
const Son = (props: SonProps) => {
  return <h1>您好,{props.name}!</h1>
}
​
// 状态组件
const Counter = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <p>你点击我 {count} 次</p>
      <button onClick={() => setCount(count + 1)}>点击我</button>
    </>
  )
}

第2章:组件化开发

2.1 函数组件 vs 类组件

TypeScript 复制代码
// 函数组件
const GreetingFn: React.FC = () => {
  return <p>Hello 我是函数组件</p>
}
​
// 类组件
class GreetingClass extends React.Component {
  render() {
    return <p>Hello 我是类组件</p>
  }
}

2.2 组件通信

TypeScript 复制代码
interface Props {
  name: string;
  age: number;
}
​
const GreetingFnProps: React.FC<Props> = (props: Props) => {
  return <p>我叫{props.name},我今年{props.age}岁了</p>
}

2.3 状态管理对比

TypeScript 复制代码
// 函数组件状态
const GreetingStateFn: React.FC = () => {
  const [count, setCount] = useState(0);
  return (
    <>
      <p>你点击了{count}次</p>
      <button onClick={() => setCount(count + 1)}>点击</button>
    </>
  )
}

第3章:基本渲染

3.1 列表渲染

TypeScript 复制代码
interface JobProps {
  id: number;
  title: string;
  company: string;
}
​
const JobItem: React.FC<{ job: JobProps }> = ({ job }) => {
  return <li>{job.id} -- {job.title} -- {job.company}</li>
}
​
const JobList: React.FC = () => {
  const jobs = [
    { id: 1, title: '前端', company: '阿里' },
    { id: 2, title: '后端', company: '腾讯' },
  ];
​
  return (
    <ul>
      {jobs.map(job => (
        <JobItem key={job.id} job={job} />
      ))}
    </ul>
  );
}

第4章:条件循环渲染

4.1 条件渲染示例

TypeScript 复制代码
const UserList: React.FC = () => {
  const [users, setUsers] = useState([
    { id: 1, name: '小王1', age: 18 },
    { id: 2, name: '小王2', age: 20 },
  ]);
  const [showList, setShowList] = useState(true);
​
  return (
    <>
      <button onClick={() => setShowList(!showList)}>
        {showList ? '隐藏列表' : '显示列表'}
      </button>
      {showList && (
        <ul>
          {users.map(user => (
            user.age > 18 ? (
              <li style={{ color: 'red' }} key={user.id}>
                {user.name} -- {user.age}
              </li>
            ) : (
              <li style={{ color: 'green' }} key={user.id}>
                {user.name} -- {user.age}
              </li>
            )
          ))}
        </ul>
      )}
    </>
  );
}

第5章:受控文本输入框

5.1 基础输入控制

TypeScript 复制代码
const Input1: React.FC = () => {
  const [text, setText] = useState('');
  return (
    <>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <p>你输入的是:{text}</p>
    </>
  )
}

5.2 登录表单

TypeScript 复制代码
const LoginForm: React.FC = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = (e: any) => {
    e.preventDefault();
    console.log(username, password);
    setUsername('');
    setPassword('');
  }

  return (
    <form onSubmit={handleSubmit}>
      <input onChange={(e) => setUsername(e.target.value)} placeholder="用户名" />
      <input onChange={(e) => setPassword(e.target.value)} placeholder="密码" />
      <button>登录</button>
    </form>
  )
}

第6章:useState Hook

6.1 基础计数器

TypeScript 复制代码
const Counter: React.FC = () => {
  const [count, setCount] = useState<number>(0);

  return (
    <>
      <button disabled={count <= 0} onClick={() => setCount(count - 1)}>-</button>
      <span>{count}</span>
      <button onClick={() => setCount(count + 1)}>+</button>
    </>
  )
}

6.2 带参数的计数器

TypeScript 复制代码
interface CounterProps {
  number: number
}

const CounterNumber: React.FC<CounterProps> = ({ number }) => {
  const [count, setCount] = useState<number>(0);
  
  return (
    <>
      <button onClick={() => setCount(count - number)}>-</button>
      <span>{count}</span>
      <button onClick={() => setCount(count + number)}>+</button>
    </>
  )
}

第7章:useEffect Hook

7.1 副作用处理

TypeScript 复制代码
const Greeting: React.FC<{ name: string }> = ({ name }) => {
  const [message, setMessage] = useState<string>('');

  useEffect(() => {
    console.log('useEffect is running.....');
    setMessage(`Hello ${name}!`);

    return () => {
      console.log('Cleanup function is running...');
    };
  }, [name]);

  return <h1>{message}</h1>
}

第8章:useContext Hook

8.1 Context状态管理

TypeScript 复制代码
interface AuthContextType {
  isAuthenticated: boolean;
  login: () => void;
  logout: () => void;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);

  const login = () => {
    setIsAuthenticated(true);
    console.log("登录成功");
  };

  const logout = () => {
    setIsAuthenticated(false);
    console.log("登出成功");
  };

  return (
    <AuthContext.Provider value={{ isAuthenticated, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error("useAuth must be used within an AuthProvider");
  }
  return context;
};

第9章:useReducer Hook

9.1 复杂状态管理

TypeScript 复制代码
interface CounterState {
  count: number;
}

type CounterAction =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'reset' }
  | { type: 'set'; payload: number };

const counterReducer = (state: CounterState, action: CounterAction): CounterState => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'reset':
      return { count: 0 };
    case 'set':
      return { count: action.payload };
    default:
      return state;
  }
};

const Counter: React.FC = () => {
  const [state, dispatch] = useReducer(counterReducer, { count: 0 });

  return (
    <div>
      <p>当前计数:{state.count}</p>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'reset' })}>重置</button>
    </div>
  );
};
第10章:useCallback Hook
10.1 性能优化
const ExpensiveButton = memo(({ onClick, label }: { onClick: () => void; label: string }) => {
  console.log(`${label} 按钮渲染了`);
  return <button onClick={onClick}>{label}</button>;
});

const WithUseCallback: React.FC = () => {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(0);

  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  return (
    <div>
      <p>计数:{count}</p>
      <p>其他状态:{otherState}</p>
      <ExpensiveButton onClick={handleClick} label="增加计数" />
      <button onClick={() => setOtherState(s => s + 1)}>改变其他状态</button>
    </div>
  );
};
第11章:useMemo Hook
11.1 缓存计算结果
const expensiveCalculation = (num: number): number => {
  console.log('执行耗时计算...');
  let result = 0;
  for (let i = 0; i < 1000000000; i++) {
    result += num;
  }
  return result;
};

const WithUseMemo: React.FC = () => {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(0);

  const expensiveValue = useMemo(() => {
    return expensiveCalculation(count);
  }, [count]);

  return (
    <div>
      <p>计算结果:{expensiveValue}</p>
      <p>其他状态:{otherState}</p>
      <button onClick={() => setCount(c => c + 1)}>增加计数</button>
      <button onClick={() => setOtherState(s => s + 1)}>改变其他状态(不会触发计算)</button>
    </div>
  );
};

第12章:useRef Hook

12.1 访问DOM元素

TypeScript 复制代码
const FocusInput: React.FC = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  const handleFocus = () => {
    inputRef.current?.focus();
  };

  return (
    <div>
      <input ref={inputRef} placeholder="点击按钮聚焦" />
      <button onClick={handleFocus}>聚焦输入框</button>
    </div>
  );
};

12.2 定时器管理

TypeScript 复制代码
const Timer: React.FC = () => {
  const [seconds, setSeconds] = useState(0);
  const [isRunning, setIsRunning] = useState(false);
  const intervalRef = useRef<number | null>(null);

  const start = () => {
    if (!isRunning) {
      setIsRunning(true);
      intervalRef.current = window.setInterval(() => {
        setSeconds(s => s + 1);
      }, 1000);
    }
  };

  const stop = () => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
      setIsRunning(false);
    }
  };

  return (
    <div>
      <p>时间:{seconds} 秒</p>
      <button onClick={start} disabled={isRunning}>开始</button>
      <button onClick={stop} disabled={!isRunning}>停止</button>
    </div>
  );
};

第13章:自定义Hooks

13.1 useLocalStorage

TypeScript 复制代码
function useLocalStorage<T>(key: string, initialValue: T): [T, (value: T) => void] {
  const [storedValue, setStoredValue] = useState<T>(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch {
      return initialValue;
    }
  });

  const setValue = (value: T) => {
    setStoredValue(value);
    window.localStorage.setItem(key, JSON.stringify(value));
  };

  return [storedValue, setValue];
}

13.2 useFetch

TypeScript 复制代码
interface UseFetchReturn<T> {
  data: T | null;
  loading: boolean;
  error: string | null;
  refetch: () => void;
}

function useFetch<T>(url: string): UseFetchReturn<T> {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const fetchData = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error('请求失败');
      const result = await response.json();
      setData(result);
    } catch (err) {
      setError(err instanceof Error ? err.message : '未知错误');
    } finally {
      setLoading(false);
    }
  }, [url]);

  useEffect(() => {
    fetchData();
  }, [fetchData]);

  return { data, loading, error, refetch: fetchData };
}

第14章:React Router

14.1 路由配置

TypeScript 复制代码
import { BrowserRouter, Routes, Route, Link, useParams, useNavigate } from "react-router-dom";

const UserDetail: React.FC = () => {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();

  return (
    <div>
      <h3>用户详情</h3>
      <p>用户 ID:{id}</p>
      <button onClick={() => navigate('/users')}>返回列表</button>
    </div>
  );
};

const App: React.FC = () => {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">首页</Link>
        <Link to="/users">用户</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/users/:id" element={<UserDetail />} />
      </Routes>
    </BrowserRouter>
  );
};

第15章:数据获取与管理

15.1 基础数据获取

TypeScript 复制代码
const BasicFetch: React.FC = () => {
  const [posts, setPosts] = useState<Post[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const fetchPosts = async () => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
        if (!response.ok) throw new Error('请求失败');
        const data = await response.json();
        setPosts(data);
      } catch (err) {
        setError(err instanceof Error ? err.message : '未知错误');
      } finally {
        setLoading(false);
      }
    };

    fetchPosts();
  }, []);

  if (loading) return <p>加载中...</p>;
  if (error) return <p style={{ color: 'red' }}>错误:{error}</p>;

  return (
    <ul>
      {posts.map(post => <li key={post.id}>{post.title}</li>)}
    </ul>
  );
};

第16章:表单处理与验证

16.1 完整表单示例

TypeScript 复制代码
interface FormData {
  username: string;
  email: string;
  password: string;
  confirmPassword: string;
}

const validateForm = (data: FormData) => {
  const errors: any = {};
  
  if (!data.username.trim()) {
    errors.username = '用户名不能为空';
  }
  
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(data.email)) {
    errors.email = '邮箱格式不正确';
  }
  
  if (data.password !== data.confirmPassword) {
    errors.confirmPassword = '两次密码不一致';
  }
  
  return errors;
};

const RegistrationForm: React.FC = () => {
  const [formData, setFormData] = useState<FormData>({
    username: '',
    email: '',
    password: '',
    confirmPassword: ''
  });
  const [errors, setErrors] = useState<any>({});

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    const validationErrors = validateForm(formData);
    setErrors(validationErrors);
    
    if (Object.keys(validationErrors).length === 0) {
      console.log('表单数据:', formData);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="username" value={formData.username} onChange={handleChange} placeholder="用户名" />
      {errors.username && <p style={{color: 'red'}}>{errors.username}</p>}
      
      <input name="email" value={formData.email} onChange={handleChange} placeholder="邮箱" />
      {errors.email && <p style={{color: 'red'}}>{errors.email}</p>}
      
      <button type="submit">注册</button>
    </form>
  );
};

第17章:状态管理方案

17.1 Context + useReducer

TypeScript 复制代码
interface AppState {
  user: User | null;
  cart: CartItem[];
  theme: 'light' | 'dark';
}

type AppAction =
  | { type: 'LOGIN'; payload: User }
  | { type: 'LOGOUT' }
  | { type: 'ADD_TO_CART'; payload: CartItem }
  | { type: 'TOGGLE_THEME' };

const appReducer = (state: AppState, action: AppAction): AppState => {
  switch (action.type) {
    case 'LOGIN':
      return { ...state, user: action.payload };
    case 'LOGOUT':
      return { ...state, user: null };
    case 'ADD_TO_CART':
      return { ...state, cart: [...state.cart, action.payload] };
    case 'TOGGLE_THEME':
      return { ...state, theme: state.theme === 'light' ? 'dark' : 'light' };
    default:
      return state;
  }
};

const AppProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [state, dispatch] = useReducer(appReducer, initialState);

  return (
    <AppContext.Provider value={{ state, dispatch }}>
      {children}
    </AppContext.Provider>
  );
};

第18章:性能优化技巧

18.1 React.memo优化

TypeScript 复制代码
const ExpensiveChild = memo(({ value, onClick }: { value: number; onClick: () => void }) => {
  console.log('ExpensiveChild 渲染了');
  return (
    <div>
      <p>值:{value}</p>
      <button onClick={onClick}>点击</button>
    </div>
  );
});

const Parent = () => {
  const [count, setCount] = useState(0);
  const [otherState, setOtherState] = useState(0);

  const handleClick = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  return (
    <div>
      <ExpensiveChild value={count} onClick={handleClick} />
      <button onClick={() => setOtherState(s => s + 1)}>改变其他状态</button>
    </div>
  );
};

第19章:Hooks最佳实践

19.1 正确处理useEffect依赖

TypeScript 复制代码
const UseEffectDependencies: React.FC = () => {
  const [count, setCount] = useState(0);

  // 正确:包含所有依赖
  useEffect(() => {
    console.log('count 变化了:', count);
  }, [count]);

  // 使用函数式更新避免依赖
  useEffect(() => {
    const timer = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    return () => clearInterval(timer);
  }, []);

  return <p>计数:{count}</p>;
};

19.2 清理副作用

TypeScript 复制代码
const CleanupDemo: React.FC = () => {
  const [isSubscribed, setIsSubscribed] = useState(false);

  useEffect(() => {
    if (!isSubscribed) return;

    const handleResize = () => console.log('窗口大小变化');
    window.addEventListener('resize', handleResize);

    return () => {
      console.log('取消订阅');
      window.removeEventListener('resize', handleResize);
    };
  }, [isSubscribed]);

  return (
    <div>
      <button onClick={() => setIsSubscribed(!isSubscribed)}>
        {isSubscribed ? '取消订阅' : '订阅'} resize 事件
      </button>
    </div>
  );
};

核心要点总结

最佳实践

  1. 类型安全:始终为组件Props定义TypeScript接口

  2. 性能优化:合理使用memo、useCallback、useMemo

  3. 状态管理:简单状态用useState,复杂状态用useReducer

  4. 副作用处理:正确设置useEffect依赖,记得清理

  5. 自定义Hooks:抽取复用逻辑,提高代码可维护性

常见错误

  1. 不要在条件语句中调用Hooks

  2. 不要忘记useEffect的清理函数

  3. 不要过度优化(memo、useCallback)

  4. 不要在render中创建对象或数组


🔗 学习资源


本教程基于实际项目的19个文件编写,每个示例都经过验证可以直接使用。从React基础到高级特性,从Hooks到性能优化,全面覆盖现代React开发所需技能。

觉得有用请点赞收藏分享!

相关推荐
liliangcsdn2 小时前
MySQL存储字节类数据的方案示例
java·前端·数据库
_Kayo_2 小时前
React useState setState之后获取到的数据一直是初始值
前端·javascript·react.js
谷哥的小弟2 小时前
HTML5新手练习项目—生命体征监测(附源码)
前端·源码·html5·项目
黎明初时2 小时前
react基础框架搭建3-配置 Redux:react+router+redux+axios+Tailwind+webpack
前端·react.js·webpack
Object~2 小时前
2.变量声明
开发语言·前端·javascript
IT_陈寒2 小时前
Vite 3实战:我用这5个优化技巧让HMR构建速度提升了40%
前端·人工智能·后端
阿干tkl2 小时前
Linux Web终端连接
linux·运维·前端
大爱编程♡2 小时前
JAVAEE-前端三剑客
java·前端·java-ee
下雨打伞干嘛2 小时前
前端学习官网文档
前端·学习