微信小程序开发008:5步实现用户登录模块与数据缓存
在微信小程序开发中,数据请求与渲染是构建动态内容的核心环节。很多开发者卡在“请求发出去没反应”或者“数据渲染不出来”的坑里,其实问题往往出在生命周期、异步处理、数据绑定这三个细节上。下面我会结合真实场景,一步步拆解如何用 wx.request 配合 setData 完成一次可靠的数据交互。
一、从“请求发出去没反应”说起——检查域名与 HTTPS
第一次写 wx.request 时,最常见的问题就是控制台打印了“请求成功”,但页面没数据。这时候先别急着怀疑代码,打开开发者工具的“详情-本地设置”,勾选“不校验合法域名”。但注意:这只是调试手段,上线前必须把接口域名配置到小程序后台的“request 合法域名”中。另外,微信强制要求 HTTPS,如果你用 HTTP 测试,会直接报错 errMsg: "request:fail"。如果后端暂时没有 HTTPS,可以用 https://api.xxx.com 这类临时方案,或者用云开发自带的云函数中转。
二、代码写对了但数据不显示?——异步与生命周期错位
看这段常见错误代码:
onLoad() {
let data = wx.request({
url: 'https://example.com/list',
success: (res) => {
return res.data;
}
});
this.setData({ list: data });
}
问题在于 wx.request 是异步的,data 在请求完成前是 undefined。正确做法是把 setData 放到 success 回调里:
onLoad() {
wx.request({
url: 'https://example.com/list',
success: (res) => {
this.setData({ list: res.data });
}
});
}
但这里还有个坑:如果页面跳转太快,onLoad 执行时组件可能还没挂载完,this.setData 会报错。保险做法是加一个 if (this.__isDestroyed) return; 判断,或者用 Promise 配合 async/await:
async onLoad() {
const res = await new Promise((resolve) => {
wx.request({
url: 'https://example.com/list',
success: resolve
});
});
this.setData({ list: res.data });
}
三、渲染列表时页面卡顿?——用 wx:for 和 key 优化
拿到数据后,一般用 wx:for 循环渲染。但如果你直接写 <view wx:for="{{list}}">,小程序会警告“Now you can provide attr 'wx:key' for a better performance”。这个警告不只是提醒,而是性能隐患。没有 key 时,小程序会按索引更新,导致列表增删时整个重新渲染。加上 wx:key="id"(其中 id 是列表数据里的唯一字段),就能实现局部更新。比如:
<view wx:for="{{list}}" wx:key="id">
{{item.name}}
</view>
如果数据没有唯一 ID,可以用 wx:key="*this",但只适用于数据本身是基本类型的情况。
四、请求失败后用户看到白屏?——错误处理与友好提示
很多教程只教 success,忽略了 fail 和 complete。实际项目中,网络波动、接口超时都很常见。建议在 fail 里显示一个简单的错误提示,并提供一个“重新加载”按钮:
wx.request({
url: 'https://example.com/list',
fail: (err) => {
this.setData({ error: true, errorMsg: '网络开小差了~' });
},
complete: () => {
wx.hideLoading();
}
});
页面里配合 wx:if 显示错误状态:
<view wx:if="{{error}}">
<text>{{errorMsg}}</text>
<button bindtap="reload">再试一次</button>
</view>
五、数据更新但界面没变?——setData 的深层对象问题
假设你有一个对象 user: { name: "张三", age: 25 },想单独修改 name,如果写 this.setData({ user.name: "李四" }) 会报错。正确做法是用字符串路径:
this.setData({ 'user.name': '李四' });
或者先拷贝整个对象再修改:
let newUser = { ...this.data.user, name: '李四' };
this.setData({ user: newUser });
另外,不要频繁调用 setData,比如在 scroll 事件里每秒更新几十次,会直接卡死。可以用防抖或节流,或者把多个更新合并成一次:
this.setData({
'user.name': '李四',
'user.age': 30,
list: newList
});
六、扩展:用 Promise 封装 wx.request,提升复用性
每次写 wx.request 都重复写 url、method、success 非常繁琐。建议封装一个通用请求函数:
const request = (url, method = 'GET', data = {}) => {
return new Promise((resolve, reject) => {
wx.request({
url,
method,
data,
header: { 'content-type': 'application/json' },
success: (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else {
reject(new Error(`请求失败,状态码:${res.statusCode}`));
}
},
fail: reject
});
});
};
// 使用
async onLoad() {
try {
const data = await request('https://example.com/list');
this.setData({ list: data });
} catch (e) {
this.setData({ error: true, errorMsg: e.message });
}
}
这样每次调用只需要关注业务逻辑,错误处理也统一了。如果遇到需要携带 token 的接口,可以在 header 里统一添加:
const token = wx.getStorageSync('token');
header: { 'Authorization': `Bearer ${token}` }
最后提一句:调试时多用 console.log 打印请求返回的数据结构,很多渲染问题其实是数据格式不对——比如后端返回了 { code: 0, data: [...] },但你直接用 res.data 赋值,结果拿到的是 { code: 0, data: [...] } 整个对象,而不是数组。这时候页面渲染 wx:for 就会报错。养成打印的习惯,能省去大量排查时间。

