零基础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开发所需技能。

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

相关推荐
weixin_382395238 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__8 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.8 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~9 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华10 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子12 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅13 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni13 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学14 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端