Remixの開発で遭遇したいろんなエラーとその対処法のメモ。個人の備忘録に近い。同じことで悩んでいる誰かの役に立てばいいなと思いここに記録残します。
Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
各ページのexport default
のReact Component Functionにasync
つけてるとこのエラーになる。loader
にasync
つけてたのでその流れで無意識にexport default async function Hogehoge()
とか書いてしまっていたが、各ページのexport default function
にはasync
つけてはいけない。
Error: You defined an action for route "routes/hogehoge.tsx" but didn't return anything from your action
function. Please return a value or null
これはメッセージの通りである。action()
を定義しているが何もreturnしてませんよ、何かしらreturnするか、少なくともnull
をreturnしなきゃだめですよ、ということを指摘している。これは実際その通りで、「サーバー処理し終わったら何事もなく自画面に戻ってきてくれればそれでいいや」という感じだったので、特に何もreturnしなかった(というかそういう発想がなかった)のだが、ただまあその程度であり、強い意図はなかった。そういう場合でも少なくともnull
返せというのがRemixの仕様らしい。はい。
Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
map
使って明細描画してるところでmap
内のロジックでuseState
使ってる場合に、明細そのものの数が増減するアクションを実行するとこのエラーになる。要するにuseState
をトップレベル以外で(動的に)使うとこうなる。こう書くと当たり前の話で素人みたいだ。。。ちなみに以下のような感じである
export async function loader({request}:LoaderFunctionArgs) {
const searchResult = await getItems(request);
return {searchResult: searchResult};
}
export default function Page() {
const data = useLoaderData<typeof loader>();
return (
<div>
<Form>
<input type="date" name="search_date" required />
<button>
search
</button>
</Form>
{data.searchResult.map((s)=>{
const [name, setName] = useState('');
const getName = async () => {
const fetchResult = await fetch('https://hogehoge.com/get-name');
const fetchResultJson = await fetchResult.json();
setName(fetchResultJson.name);
};
return (
<div key={s.id}>
<div>
{s.id}
</div>
<div>
{name !== '' ? <p>{name}</p> : <></>}
</div>
<div>
<button onClick={getName}>
get name
</button>
</div>
</div>
);
})}
</div>
);
}
この例だとconst [name, setName] = useState('');
がdata.searchResult.map((s)=>{...
の中におり、最初の検索のときにはまだ動作するが、search_date
を変えて検索して再描画し、検索結果(searchResult
)の件数が変わると、表題のエラーになる。useState
を一番上に持ってこないとだめ(ただこの場合はuseState
後の描画のリフレッシュの考慮が多分必要になる)。あるいはこの部分(<button onClick={getName}>get name</button>
とgetName()
でsetName
するところ)をコンポーネントとして別に切り出すかする必要がある。
TypeError: Cannot convert argument to a ByteString because the character at index XX has a value of YY which is greater than 255.
XXとYYには数値が入る。これはredirect
の引数に渡すURLの文字列に全角文字などのマルチバイトキャラクターをURLエンコードせずにそのまま渡すと発生する。return redirect('/hogehoge?param=ほげほげ');
のようなもの。対策は簡単で、事前にencodeURI
すればいいだけ。
const uri = encodeURI('/hogehoge?param=ほげほげ');
return redirect(uri);
versionなど
"@remix-run/node": "^2.16.6",
"@remix-run/react": "^2.16.6",
"@remix-run/serve": "^2.16.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
$ node --version
v20.18.1